score:1

Accepted answer

Your example is complicated. I'll first state and solve a simpler problem, then use the same method to solve your original problem.


I want to split a list of numbers into contiguous groups of even and odd numbers. For example, given the list 2,2,4,3,6,2 I would split it into three groups [2,2,4], [3], [6,2]

This can be done concisely with a GroupAdjacentBy method

> var numbers = new List<int>{2,2,4,3,6,2};
> numbers.GroupAdjacentBy(x => x % 2)
[[2,2,4], [3], [6,2]]

To solve your problem, simply replace the even-odd classifying function above with your classification function:

> var points = new List<int>{-180,180};
> var f = new Func<int,int>(x => points.BinarySearch(x));
> var numbers = new List<int>{6,-50,100,190,200,20};
> numbers.GroupAdjacentBy(f)
[[6,-50,100], [190,200], [20]]

score:0

If you need the collections to be updated as soon as the values change why don;t you use properties? Something like

// your original collection
public IList<double> OriginalValues; //= new List<double> { -1000, 5, 7 1000 };

public IList<double> BelowMinus180
{
   get { return OriginalValues.Where(x => x < -180).ToList().AsReadOnly(); }
}

public IList<double> BetweenMinus180And180
{
   get { return OriginalValues.Where(x => x >= -180 && x <= 180).ToList().AsReadOnly(); }
}

public IList<double> Above180
{
   get { return OriginalValues.Where(x => x > 180).ToList().AsReadOnly(); }
}

score:0

public static List<List<T>> PartitionBy<T>(this IEnumerable<T> seq, Func<T, bool> predicate)
{
    bool lastPass = true;
    return seq.Aggregate(new List<List<T>>(), (partitions, item) =>
    {
        bool inc = predicate(item);
        if (inc == lastPass)
        {
            if (partitions.Count == 0)
            {
                partitions.Add(new List<T>());
            }
            partitions.Last().Add(item);
        }
        else
        {
            partitions.Add(new List<T> { item });
        }
        lastPass = inc;
        return partitions;
    });
}

You can then use:

List<List<double>> segments = newDataSet.PartitionBy(d => d > -180 && d < 180);

score:0

How about this possible solution using two passes. In the first pass we find the indices were a change occurs, and in the second pass we do the actual partitioning. First an auxiliary method to determine the category:

    protected int DetermineCategory(double number)
    {
        if (number < 180 && number > -180)
            return 0;
        else if (number < -180)
            return 1;
        else
            return 2;
    }

And then the actual algorithm:

    List<int> indices = new List<int>();
    int currentCategory = -1;
    for (int i = 0; i < numbers.Count; i++)
    {
        int newCat = DetermineCategory(numbers[i]);
        if (newCat != currentCategory)
        {
            indices.Add(i);
            currentCategory = newCat;
        }
    }
    List<List<double>> collections = new List<List<double>>(indices.Count);
    for (int i = 1; i < indices.Count; ++i)
        collections.Add(new List<double>(
            numbers.Skip(indices[i - 1]).Take(indices[i] - indices[i - 1])));

score:0

Here is a new answer based on the new info you provided. I hope this time I will be closer to what you need

public IEnumerable<IList<double>> GetCollectionOfCollections(IList<double> values, IList<double> boundries)
{
    var ordered = values.OrderBy(x => x).ToList();
    for (int i = 0; i < boundries.Count; i++)
    {
        var collection = ordered.Where(x => x < boundries[i]).ToList();
        if (collection.Count > 0)
        {
            ordered = ordered.Except(collection).ToList();
            yield return collection.ToList();
        }
    }
    if (ordered.Count() > 0)
    {
        yield return ordered;
    }
}

score:0

One method with linq. Untested but should work

var firstSet = dataSet.TakeWhile(x=>x>-180&&x<180);
var totalCount = firstSet.Count();
var secondSet = dataSet.Skip(totalCount).TakeWhile(x=>x<-180);
totalCount+=secondSet.Count();
var thirdSet = dataSet.Skip(totalCount).TakeWhile(x=>x>180);
totalCount += thirdSet.Count();
var fourthSet = dataSet.Skip(totalCount);

Related Articles