C# - Selecting data from an array when the data is random in content and of unknown length

94 views Asked by At

So I wrote some code and was told it was poor form to write it in this way.

So hoping someone can point me towards a better way. My code:

string phrase = Value.Text;
List<string> wordList = new List<string>();
string words = phrase.Split('\t', '\r');

int Three = 3;
int Two = 2;
int One = 1;
int Four = 4;
int Five = 5;
int Six = 6;

for (int i = 0; i < result; i = i + 12, Three = Three + 12, 
Two = Two + 12, One = One + 12, Four = Four + 12, Five = Five + 12, 
Six = Six + 12)
{
wordList.Add(ID.Text + '\t');
wordList.Add(IT.Text + '\t');
wordList.Add(words[Three] + '\t');
wordList.Add(words[Two] + '\t');
wordList.Add(PD.Text + '\t');
....etc.
}

The offending part is this:

for (int i = 0; i < result; i = i + 12, Three = Three + 12, 
    Two = Two + 12, One = One + 12, Four = Four + 12, Five = Five + 12, 
    Six = Six + 12)

I can see why, it is pretty ugly and quite long, perhaps unnecessarily so?

What are you trying to do?

I have an array of data (phrase) that is entirely random.

The data is entered in sets of 12, but more than one data set can be entered, but always divisible by 12 - so 12, 24, 36. I do not know how much data will be entered at any given point, but I know it will be divisible by 12.

Sometimes words, sometimes numbers - I do not know in advance what it will be, they are not days, they are not ages, I cannot specify an element to the data points in the array. They will be varying in character length, they will have different punctuation marks in different places in each data set. All of the data is separated by a Tab.

From the list of 12, I need to pull, the 3, 2, 1, 4, 5, 6.

In that order. I then place that data into a List<> and output the data, along with some text boxes to match a specified format.

Purpose of the code:

To loop through the data in sets of 12, until there is no more data.

Each loops pulls a data point from the array, for one example, the 3rd, 15th, 27th, 39th etc.

Each loop adds the data from the words array, adds TextBoxes in various places and then compiles them in a List. The List is then produced for the user to copy into a specified format in a single action.

I thought up the "int Three = 3;" for the purpose of being able to increase that number by 12 each loop. I couldn't think of any other way to do it.

But here to learn, so if you know how it should be done - I am all ears, even if you just want to point me to what I should be doing.

If you need an example of the data, face palm your keyboard 12 times putting a tab between each one...you will have an idea of what the data is - there is absolutely no point me providing an example, it is meaningless gibberish, the only factor that is consistent is the Tab between each grouping.

1

There are 1 answers

3
asawyer On

To long for a comment - Here's a prospective solution implementing what I outlined earlier. It breaks the input into 12 length chunks and creates a temporary collection of word sets that could be used for whatever purpose you need with comments explaining how it works.

void Main()
{
    int demoDataSetCount = 10;
    int chunkSize=12;
    //create some test data as a multiple of the chunk size
    var inputData = string.Join(Environment.NewLine, Enumerable.Range(0, demoDataSetCount * chunkSize)
        .Select(e => string.Join("\t", Enumerable.Range(e, chunkSize))));
    
    //call the extension method
    var wordSets = inputData.GenerateWordSets(chunkSize);
    
    //loop over the resulting collection
    foreach(var wordSet in wordSets)
    {
        //get the various interesting items by index
        var three=wordSet.Values.ElementAt(2);
        var two=wordSet.Values.ElementAt(1);
        var one=wordSet.Values.ElementAt(0);
        var four=wordSet.Values.ElementAt(3);
        var five=wordSet.Values.ElementAt(4);
        var six=wordSet.Values.ElementAt(5);

        //write to console demo'ing output
        Console.WriteLine($"Index: {wordSet.Index}{Environment.NewLine}\tThree: {three}{Environment.NewLine}\tTwo: {two}{Environment.NewLine}\tOne: {one}{Environment.NewLine}\tFour: {four}{Environment.NewLine}\tFive: {five}{Environment.NewLine}\tSix: {six}");
    }
}

//used to hold the intermediate output, one set of words per chunk size
public sealed class WordSet
{
    public int Index { get; set; }
    public IEnumerable<string> Values { get; set; }
}

public static class Extensions
{
    //various optional parameters to tweak behavior
    public static IEnumerable<WordSet> GenerateWordSets(this string input, int chunkSize=12, int interestingRangeStart=0, int interestingRangeLength=6)
    {
        //split the input on new line and tabs
        var words = input.Split(new string[] { Environment.NewLine, "\t" }, StringSplitOptions.None);
        //generate a range of ints to group with
        return Enumerable.Range(0, words.Length)
            //int rounding used to group into chunks
            //get the words from the current index
            .GroupBy(k => k / chunkSize, k=> words[k])
            //project grouping into a WordSet collection
            .Select(g => new WordSet 
            { 
                Index = g.Key,
                //take only the indexes we are interested in reading
                Values = g.Skip(interestingRangeStart).Take(interestingRangeLength) 
            });
    }
}

See https://stackoverflow.com/a/1008974/426894 for more on how the grouping works here.

Input like this:

0 1 2 3 4 5 6 7 8 9 10 11
1 2 3 4 5 6 7 8 9 10 11 12
2 3 4 5 6 7 8 9 10 11 12 13
....

Generates Output like:

Index: 0
  Three: 2
  Two: 1
  One: 0
  Four: 3
  Five: 4
  Six: 5
Index: 1
  Three: 3
  Two: 2
  One: 1
  Four: 4
  Five: 5
  Six: 6
Index: 2
  Three: 4
  Two: 3
  One: 2
  Four: 5
  Five: 6
  Six: 7
....