Home > Mobile >  .NET collections: How to get a new list from an existing list between start to end value
.NET collections: How to get a new list from an existing list between start to end value

Time:07-26

I have a string list. I need to create a separate list based on all entries between a set of start and end values, including those start and end values, where there may be multiple such sequences.

var stringList = {
    "16a_Start", "test1", "test11", "16a_End",
    "15a_start", …, "15a_end",
    "16a_Start", "test2", "test22", "16a_End",
    "15a_start", …, "15a_end"
}    

This should result in e.g.,

var 16aList = { 
    { "16a_Start", "test1", "test11", "16a_End" },
    { "16a_Start", "test2", "test22", "16a_End"}
}    

Similarly for 15aList.

CodePudding user response:

As mentioned in the comments (reference), you're likely going to find this more intuitive to solve via a while loop. That's because LINQ, like SQL, is optimized for set-based queries. By contrast, since this requires keeping track of the start and end position of the various segments, it's easier to solve with a procedural approach.

General Approach

The basic idea in the procedural approach is, given an array and a segment key (e.g., 16a), to find the positions in the array that correspond to the start segment (e.g., 16a_Start) and the end segment (e.g., 16a_end), copy the data between those positions, and add them to an array of output. Once that's done, we'll repeat this, starting at the position of the end segment.

Implementation Details

To implement this, we can use the following methods built into the .NET base class library:

  • Array.IndexOf() will allow us to get the position of the start or end segment, thus defining the range of any one block.
  • Array.Copy() will allow us to copy elements of the source array starting at the start segment, for the specified length of the segment.

Sample Code

Here's a rough example of how we might approach this. This isn't intended to be final code, but rather a proof-of-concept to get you started.

public string[][] ExtractSegment(string[] values, string segmentKey)
{
    var currentIndex        = 0;
    var output              = new List<String[]>();
    while (currentIndex >= 0)
    {
        var startIndex      = Array.IndexOf(values, $"{segmentKey}_Start", currentIndex);
        if (startIndex >= 0)
        {
            var endIndex    = Array.IndexOf(values, $"{segmentKey}_End", startIndex);
            var length      = endIndex-startIndex 1;
            var segment     = new string[length];
            Array.Copy(values, startIndex, segment, 0, length);
            output.Add(segment);
            currentIndex    = endIndex;
        }
        else 
        {
            currentIndex    = startIndex;
        }
    }
    return output.ToArray();
}

Testing

You can test this with the following:

string[] stringList = {
    "16a_Start", "test1", "test11", "16a_End",
    "15a_start", "test1", "test11", "15a_end",
    "16a_Start", "test2", "test22", "16a_End",
    "15a_start", "test1", "test11", "15a_end"
};
var 16a = ExtractSegment(stringList, "16a");

Limitations

This code assumes that there will always be a corresponding end segment (e.g., 16a_End) for every start segment (e.g., 16a_Start). It also assumes that these will be sequential; i.e., that the segments won't overlap. This may or may not be a valid assumption depending on how clean or reliable your data source is. The above code will give you a good foundation to work from, but a more robust, production ready implementation will include additional checks to validate the data integrity.

Conclusion

Note that there very well may be a clever use of LINQ to solve this—and, if I have some extra time, I'll put some thought into that. But my suspicion is that, even if there is, the procedural approach will be more straight-forward to read, and will be much easier to add code to handle possible issues with the data. Similarly, there are some syntactical shortcuts that could make the above code tidier, but the longer form makes it easier to read and reason through.

  • Related