9

私が持っている場合、例えば、次List<int>

{ 1, 2, 3, 4 } //list1
{ 2, 3, 5, 6 } //list2
...
{ 3, 4, 5 }    //listN

次の対応するを取得するための最良の方法は何List<int?>ですか?

{    1, 2,    3,    4,    null, null } //list1
{ null, 2,    3,    null, 5,    6    } //list2
...
{ null, null, 3,    4,    5,    null } //listN
4

2 に答える 2

7

チャットで話し合った解決策を投稿します。ルーピー/フィルタリングのすべてにLinqを使用した最適化されていないバージョンがありました。

ただし、作成されたすべての列挙子クラスと、途中でコレクションがインスタンス化/変更されるため、パフォーマンスはあまり高くないと思います。

そのため、コレクションを変更するのではなく、アクティブなイテレーターを追跡する管理機能を使用して、時間をかけて手書きのループに最適化しました。ここにあります:iters

完全なライブ デモについては、 http://ideone.com/FuZIDyを参照してください。

カスタム比較子DefaultComparer<T>なしでLinqのMin()拡張メソッドを使用しているため、リストはによって事前に並べられていると想定しています

public static IEnumerable<IEnumerable<T>> AlignSequences<T>(this IEnumerable<IEnumerable<T>> sequences)
{
    var iters = sequences
        .Select((s, index) => new { active=true, index, enumerator = s.GetEnumerator() })
        .ToArray();

    var isActive = iters.Select(it => it.enumerator.MoveNext()).ToArray();
    var numactive = isActive.Count(flag => flag);

    try
    {
        while (numactive > 0)
        {
            T min = iters
                .Where(it => isActive[it.index])
                .Min(it => it.enumerator.Current);

            var row = new T[iters.Count()];

            for (int j = 0; j < isActive.Length; j++)
            {
                if (!isActive[j] || !Equals(iters[j].enumerator.Current, min)) 
                    continue;

                row[j] = min;
                if (!iters[j].enumerator.MoveNext())
                {
                    isActive[j] = false;
                    numactive -= 1;
                }
            }
            yield return row;
        }
    }
    finally
    {
        foreach (var iter in iters) iter.enumerator.Dispose();
    }
}

次のように使用します。

public static void Main(string[] args)
{
    var list1 = new int?[] { 1, 2, 3, 4, 5 };
    var list2 = new int?[] { 3, 4, 5, 6, 7 };
    var list3 = new int?[] { 6, 9, 9 };

    var lockstep = AlignSequences(new[] { list1, list2, list3 });

    foreach (var step in lockstep)
        Console.WriteLine(string.Join("\t", step.Select(i => i.HasValue ? i.Value.ToString() : "null").ToArray()));
}

印刷されます(デモ目的で、結果を横向きに印刷します):

1       null    null
2       null    null
3       3       null
4       4       null
5       5       null
null    6       6
null    7       null
null    null    9
null    null    9

注: 単一のシーケンス シーケンスではなく、任意の数のリストを受け入れるようにインターフェイスを変更することをお勧めします。

public static IEnumerable<IEnumerable<T>> AlignSequences<T>(params IEnumerable<T>[] sequences)

そうすれば、あなたはただ呼び出すことができます

var lockstep = AlignSequences(list1, list2, list3);
于 2012-11-22T13:39:32.630 に答える
1

を使用した別のアプローチを次に示しList.BinarySearchます。

サンプルデータ:

var list1 = new List<int>() { 1, 2, 3, 4 };
var list2 = new List<int>() { 2, 3, 5, 6, 7, 8 }; 
var list3 = new List<int>() { 3, 4, 5 };
var all   = new List<List<int>>() { list1, list2, list3 };

最小/最大およびすべての nullable リストを計算します。

int min = all.Min(l => l.Min());
int max = all.Max(l => l.Max());
// start from smallest number and end with highest, fill all between
int count = max - min + 1;  

List<int?> l1Result = new List<int?>(count);
List<int?> l2Result = new List<int?>(count);
List<int?> l3Result = new List<int?>(count);

foreach (int val in Enumerable.Range(min, count))
{
    if (list1.BinarySearch(val) >= 0)
        l1Result.Add(val);
    else
        l1Result.Add(new Nullable<int>());

    if (list2.BinarySearch(val) >= 0)
        l2Result.Add(val);
    else
        l2Result.Add(new Nullable<int>());

    if (list3.BinarySearch(val) >= 0)
        l3Result.Add(val);
    else
        l3Result.Add(new Nullable<int>());
}

出力:

Console.WriteLine(string.Join(",", l1Result.Select(i => !i.HasValue ? "NULL" : i.Value.ToString())));
Console.WriteLine(string.Join(",", l2Result.Select(i => !i.HasValue ? "NULL" : i.Value.ToString())));
Console.WriteLine(string.Join(",", l3Result.Select(i => !i.HasValue ? "NULL" : i.Value.ToString())));

1,      2,      3,      4,      NULL,   NULL,   NULL,   NULL
NULL,   2,      3,      NULL,   5,      6,      7,      8
NULL,   NULL,   3,      4,      5,      NULL,   NULL,   NULL

デモ

于 2012-11-22T14:36:30.113 に答える