c# - 对齐多个排序列表

标签 c# linq

如果我有,例如以下 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

最佳答案

我正在发布我们在聊天中讨论的解决方案。我有一个未优化的版本,使用 Linq 进行循环/过滤:

但是,我怀疑它不会太高效,因为创建了所有枚举器类,并且在此过程中实例化/修改了集合。

所以我花时间优化它到手写的循环与管理跟踪活跃的迭代器而不是修改iters收藏。在这里:

参见 http://ideone.com/FuZIDy 完整的现场演示。

Note I assume the lists are pre-ordered by DefaultComparer<T>, since I use Linq'sMin() extension method without a custom comparer

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);

关于c# - 对齐多个排序列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13513789/

相关文章:

c# - 使用 MethodBuilder 生成动态 IL 时是否可以跳过可见性检查?

c# - .NET 调试问题

c# - 在 select new 中使用 List<> 加入 LINQ

sql-server - 停止 LINQ to SQL 在插入后执行 select 语句

c# - 如何使用 web api 在请求头中添加 api key

c# - 无法在 Aspx 页面中从 Codebehind 运行 Javascript 代码

c# - AutoMapper Project().To() 并对子集合进行排序

sql - 有什么方法可以使用 LINQ 进行 MDX 查询吗?

c# - 你如何在 Select 方法中使用别名 (LINQ)

c# - 使用 LINQ 对项目进行分组并从每个组中选择特定项目