4

数値のコレクション (コレクション) があり、任意のサイズにすることができ、負の数と正の数を含めることができます。いくつかの基準に基づいて分割しようとしています。コレクションの最初の数字から始めて、その数字が -180 を超えて 180 未満である間にコレクションを作成したいと考えています。数値が再び許容範囲内になると、それらは再び新しいコレクションに入れられます。問題は、コレクションを整理する必要があることです。

例えば。

100個のコレクションを取る:

  • 最初の 50 は 180 から -180 の間です。
  • 次の 20 は -180 未満です
  • 次の 20 は 180 を超えています
  • 最後の 10 個は 180 から -180 の間です

上記のコレクションから、元の 1 つのコレクションと同じ順序で 4 つの個別のコレクションが必要です。

  • 180 から -180 までの元の順序での最初のコレクション番号
  • -180 未満の元の順序での 2 番目のコレクション番号
  • 180 を超える元の順序での 3 番目のコレクション番号
  • 180 から -180 までの元の順序での 4 番目のコレクション番号

私は試みましたが、私が持っているものは機能せず、if ステートメントの厄介な混乱です。私はlinqをよく知りませんが、それを使用したよりエレガントなソリューションがあると思います。linq ステートメントを作成する方法を教えてくれたり、if ステートメントを機能させる方法が最善の方法である場合は提案したりして、誰か助けてくれませんか。

Collection<Tuple<Collection<double>, int>> collectionOfDataSets = new Collection<Tuple<Collection<double>, int>>();
Collection<double> newDataSet = new Collection<double>();
for (int i = 0; i < dataSet.Count; i++) {
    if (dataSet[i] < 180 && dataSet[i] > -180) {
        newDataSet.Add(dataSet[i]);
    } else {
        Tuple<Collection<double>, int> lastEntry = collectionOfDataSets.LastOrDefault(b => b.Item2 == i--);
        if (lastEntry != null){
            lastEntry.Item1.Add(dataSet[i]);
        }
        double lastInLastCollection = collectionOfDataSets.ElementAtOrDefault(collectionOfDataSets.Count).Item1.Last();
        if (newDataSet.Count > 0 && lastInLastCollection!= dataSet[i]){
            collectionOfDataSets.Add(new Tuple<Collection<double>, int>(newDataSet, i));                        
        }
        newDataSet = new Collection<double>();
    }
}

よろしくお願いいたします。

4

6 に答える 6

1

あなたの例は複雑です。最初に、より単純な問題を述べて解決し、次に同じ方法を使用して元の問題を解決します。


数字のリストを連続する偶数と奇数のグループに分割したいと考えています。たとえば、リストが与えられた場合、それを3 つのグループ2,2,4,3,6,2に分割します[2,2,4], [3], [6,2]

これはGroupAdjacentByメソッドで簡潔に行うことができます

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

問題を解決するには、上記の偶奇分類関数を独自の分類関数に置き換えるだけです。

> 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]]
于 2013-01-15T23:46:15.260 に答える
0

linq を使用した 1 つのメソッド。テストされていませんが、動作するはずです

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);
于 2013-01-16T00:56:58.197 に答える
0

値が変更されたらすぐにコレクションを更新する必要がある場合、なぜプロパティを使用しないのでしょうか? 何かのようなもの

// 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(); }
}
于 2013-01-15T22:40:54.767 に答える
0

2 つのパスを使用したこの可能な解決策はどうですか。最初のパスで変更が発生したインデックスを見つけ、2 番目のパスで実際のパーティショニングを行います。まず、カテゴリを決定するための補助的な方法:

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

そして、実際のアルゴリズム:

    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])));
于 2013-01-15T22:56:06.960 に答える
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;
    });
}

その後、次を使用できます。

List<List<double>> segments = newDataSet.PartitionBy(d => d > -180 && d < 180);
于 2013-01-15T22:43:03.733 に答える
0

これは、あなたが提供した新しい情報に基づく新しい回答です。今回はあなたが必要とするものに近づくことを願っています

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;
    }
}
于 2013-01-15T23:33:23.753 に答える