views:

56

answers:

1

Ok, so hopefully I can explain this in enough detail for somebody to be able to help me.. I am writing a program in C# that is supposed to take a text file and replace specific text, which happen to be names of files, and print a new text file for every single combination of the given filenames. The specific places to change the text of filenames have their own set of possible filenames, listed as an array described below. The program should run regardless of how many filenames are available for each location as well as how many total locations for the filenames. If you really wanted to make it awesome, it can be slightly optimized knowing that no filenames should be duplicated throughout any single text file.

text is an array of lines that make up the base of the total file.

lineNum holds an array of the line locations of the filename entries.

previousFiles is an array of previously used filenames, starting with what is already in the file.

files is a jagged 2-dimensional array of possible filenames where files[1] would be an array of all the possible filenames for the 2nd location

Here is an example of how it would work with 3 separate filename locations, the first one given 3 possible filenames, the second given 8 possible filenames, and the third given 3 possible filenames.

Oh and assume buildNewFile works.

        int iterator = 0;
        for (int a = 0; a < 3; a++)
        {
            for (int b = 0; b < 8; b++)
            {
                for (int c = 0; c < 3; c++)
                {
                    iterator++;
                    text[lineNums[0]] = text[lineNums[0]].Replace(previousFiles[0], files[0][a]);
                    text[lineNums[1]] = text[lineNums[1]].Replace(previousFiles[0], files[0][a]);
                    text[lineNums[2]] = text[lineNums[2]].Replace(previousFiles[1], files[1][b]);
                    text[lineNums[3]] = text[lineNums[3]].Replace(previousFiles[1], files[1][b]);
                    text[lineNums[4]] = text[lineNums[4]].Replace(previousFiles[2], files[2][c]);
                    text[lineNums[5]] = text[lineNums[5]].Replace(previousFiles[2], files[2][c]);
                    previousFiles = new string[] { files[0][a], files[1][b], files[2][c] };
                    buildNewFile(text, Info.baseFolder + "networks\\" + Info.dsnFilename + iterator + ".dsn");
                }
            }
        }

If you guys can help me, thank you so much, I just can't figure out how to do it recursively or anything. If you have any questions I'll answer them and edit up here to reflect that.

+1  A: 

It took me a little while to figure out what you really wanted to do. This problem can be solved without recursion, the trick is to look at the data you have and get it into a more usable format.

Your "files" array is the one that is the most inconvenient. The trick is to transform the data into usable permutations. To do that, I suggest taking advantage of yield and using a method that returns IEnumerable. The code for it is here:

public IEnumerable<string[]> GenerateFileNameStream(string[][] files)
{
    int[] current_indices = new int[files.Length];
    current_indices.Initialize();
    List<string> file_names = new List<string>();

    while (current_indices[0] < files[0].Length)
    {
        file_names.Clear();

        for (var index_index = 0; index_index < current_indices.Length; index_index++)
        {
            file_names.Add(files[index_index][current_indices[index_index]]);
        }

        yield return file_names.ToArray();

        // increment the indices, trickle down as needed
        for (var check_index = 0; check_index < current_indices.Length; check_index++)
        {
            current_indices[check_index]++;

            // if the index hasn't rolled over, we're done here
            if (current_indices[check_index] < files[check_index].Length) break;

            // if the last location rolls over, then we are totally done
            if (check_index == current_indices.Length - 1) yield break;

            // reset this index, increment the next one in the next iteration
            current_indices[check_index] = 0;
        }
    }
}

Basically, it keeps track of the current index for each row of the files 2D array and returns the file name at each current index. Then it increments the first index. If the first index rolls over, then it resets to 0 and increments the next index instead. This way we can iterate through every permutation of the file names.

Now, looking at the relationship between lineNum and files, I assume that each location in the file is copied to two lines. The rest of the code is here:

public void MakeItWork(string[][] files, int[] lineNum, string[] text, string[] previousFiles)
{
    var iterator = 0;
    var filenames = GenerateFileNameStream(files);

    // work a copy of the text, assume the "previousFiles" are in this text
    var text_copy = new string[text.Length];

    foreach (var filenameset in filenames)
    {
        iterator++;
        Array.Copy(text, text_copy, text.Length);

        for (var line_index = 0; line_index < lineNum.Length; line_index++)
        {
            var line_number = lineNum[line_index];
            text[line_number] = text[line_number].Replace(previousFiles[line_index], filenameset[line_index / 2]);
        }

        buildNewFile(text_copy, Info.baseFolder + "networks\\" + Info.dsnFilename + iterator + ".dsn");
    }
}

This code just takes the results from the enumerator and generates the files for you. The assumption based on your sample code is that each filename location is used twice per file (since the lineNum array was twice as long as the files location count.

I haven't fully tested all the code, but the crux of the algorithm is there. The key is to transform your data into a more usable form, then process it. The other suggestion I have when asking a question here is to describe the problem more as a "problem" and not in the terms of your current solution. If you detailed the goal you are trying to achieve instead of showing code, you can get more insights into the problem.

Garo Yeriazarian