0

辞書の各キーには、多数の整数のリストがありますすべてのリストのすべてのアイテムを反復処理するまで、各キーを反復処理し、リストから n 個のアイテムを取得するたびにそれを実行する必要があります。それを実装する最良の方法は何ですか?列挙子を実装する必要がありますか?

コード:

enum ItemType { Type1=1, Type2=2, Type3=3 };

var items = new Dictionary<ItemType, List<int>>();
items[ItemType.Type1] = new List<int> { 1, 2, 3, 4, 5 };
items[ItemType.Type2] = new List<int> { 11, 12, 13, 15 };
items[ItemType.Type3] = new List<int> { 21, 22, 23, 24, 25, 26 };

例: n=2。

  1. 1 回目の反復では 1,2,11,12,21,22 が返されます
  2. 2 回目の反復では 3,4,13,15,23,24 が返されます
  3. 3 回目の繰り返しは 5,25,26 を返します

更新: 最後に、このアイテムのリストを次の順序で取得する必要があります: 1,2,11,12,21,22, 3,4,13,15,23,24, 5,25,26

4

4 に答える 4

1

これがどのように行われるかは次のとおりです。

enum ItemType { Type1 = 1, Type2 = 2, Type3 = 3 };

Dictionary<ItemType, List<int>> items = new Dictionary<ItemType, List<int>>();
items[ItemType.Type1] = new List<int> { 1, 2, 3, 4, 5 };
items[ItemType.Type2] = new List<int> { 11, 12, 13, 15 };
items[ItemType.Type3] = new List<int> { 21, 22, 23, 24, 25, 26 };

// Define upper boundary of iteration
int max = items.Values.Select(v => v.Count).Max();

int i = 0, n = 2;
while (i + n <= max)
{
    // Skip and Take - to select only next portion of elements, SelectMany - to merge resulting lists of portions
    List<int> res = items.Values.Select(v => v.Skip(i).Take(n)).SelectMany(v => v).ToList();
    i += n;

    // Further processing of res
}
于 2012-06-07T08:48:13.660 に答える
0

カスタム列挙子を定義する必要はありません。MoveNext手動で使用するだけです。

ステップ1、あなたをに変換しDictionary<ItemType, List<int>>ますDictionary<ItemType, List<IEnumerator<int>>

var iterators = items.ToDictionary(p => p.Key, p => (IEnumerator<int>)p.Value.GetEnumerator());

ステップ 2:MoveNext手動で処理:

public List<int> Get(Dictionary<ItemType, IEnumerator<int>> iterators, int n)
{
    var result = new List<int>();

    foreach (var itor in iterators.Values)
    {
        for (var i = 0; i < n && itor.MoveNext(); i++)
        {
            result.Add(itor.Current);
        }
    }

    return result;
}

Get複数回呼び出すと、期待どおりの結果が得られます。列挙子自体は現在の位置を保持します。

于 2012-06-07T08:46:22.713 に答える
0

これはあなたのためにそれを行います:

var resultList = new List<int>();
items.ToList().ForEach(listInts => resultList.AddRange(listInts.Take(n));

これにより、LINQ 拡張機能に面倒な作業を任せることができます。Take()は、存在する以上のものを要求した場合、例外をスローせずに可能な限り取得します。この場合、結果を別のリストに追加していますが、結果を反復するために、末尾に別のForEach()を簡単にタグ付けすることもできます。Take()

シーケンスの例から、 x開始点からn個のアイテムを取得していることに気付きました。質問を編集して開始点の決定方法を含める場合は、例を調整します。


編集:

返される要素がなくなるまで、各反復から各リストからn個のアイテムを取得する必要があるため、次のようにします。

class Program
{
    static void Main(string[] args)
    {

        var items = new Dictionary<ItemType, List<int>>();
        items[ItemType.Type1] = new List<int> { 1, 2, 3, 4, 5 };
        items[ItemType.Type2] = new List<int> { 11, 12, 13, 15 };
        items[ItemType.Type3] = new List<int> { 21, 22, 23, 24, 25, 26 };

        int numItemsTaken = 0;
        var resultsList = new List<int>();
        int n = 2, startpoint = 0, previousListSize = 0;

        do
        {
            items.ToList().ForEach(x => resultsList.AddRange(x.Value.Skip(startpoint).Take(n)));
            startpoint += n;
            numItemsTaken = resultsList.Count - previousListSize;
            previousListSize = resultsList.Count;
        } 
        while (numItemsTaken > 0);

        Console.WriteLine(string.Join(", ", resultsList));
        Console.ReadKey();
    }

    enum ItemType { Type1 = 1, Type2 = 2, Type3 = 3 };
}

do whileこれはループを使用する数少ない例の 1 つでありn、リストのサイズやサイズ、またはリストの数に関係なく機能します。

于 2012-06-07T08:38:10.893 に答える
0

「最善の方法」は、読みやすさやパフォーマンスなどの目標によって異なります。

1 つの方法を次に示します。

var firstIter = items.Values.SelectMany(list => list.Take(2));
var secondIter = items.Values.SelectMany(list => list.Skip(2).Take(2));
var thirdIter = items.Values.SelectMany(list => list.Skip(4).Take(2));

var finalResult =  firstIter.Concat(secondIter).Concat(thirdIter);

編集:これはより一般的なバージョンです:

var finalResult = Flatten(items, 0, 2);

IEnumerable<int> Flatten(
    Dictionary<ItemType, List<int>> items, 
    int skipCount, 
    int takeCount)
{
    var iter = items.Values.SelectMany(list => list.Skip(skipCount).Take(takeCount));

    return
        iter.Count() == 0 ?  // a bit inefficient here
        iter :
        iter.Concat(Flatten(items, skipCount + takeCount, takeCount));
}
于 2012-06-07T08:50:23.710 に答える