在LINQ中解压缩已压缩的列表

3
在一个糟糕的界面中,我们有以下问题:
int[] userIdList; // ids of all users to display
string[] userNameList; // names of all users to display

以 userIdList[i] 始终包含 userNameList[i] 的用户ID为限制条件,新的要求是按名称对用户进行排序: 我将采取这两个列表,按名称排序,并返回两个列表,其中前述限制仍然有效。
当然,我可以自己实现一个排序功能,但我认为单行LINQ语句可以做得更好?我已经达到了:
userNameList.Zip(userIdList, (name, id) => new {name, id}).OrderBy(a=>a.name).

但是现在我不知道如何再次解压列表...


如果可能的话,我建议不要将它们保持为未压缩状态,而是尽量将它们合并成一个单一的对象,以确保将来的操作更容易处理。一旦从接口获取到Id和Names,就将它们合并到一个User对象中,并尽量多地使用该对象。如果需要分别使用它们中的一个,你仍然可以使用Tim Schmelter建议的语法。 - Nzall
@NateKerkhofs 排序将在中间件中发生,这些数组只是在从后端传递到前端的过程中通过。我猜测在前端它们将再次被压缩以进行显示 叹气 - Alexander
4个回答

7
int[] userIdList = zipped.Select(x => x.id).ToArray();
string[] userNameList = zipped.Select(x => x.name).ToArray();

为了使您的解决方案正常工作,zipped 集合应该是一个列表,因为它执行了多个枚举。无法对可枚举对象进行解压缩。因为解压缩后,您通常会期望得到两个独立的可枚举集合,而这两个集合不能来自同一个可枚举集合。因为您只能枚举一次。 - zafar

2

对于输入:

 int[] userIdList = new []{ 1,5,3,6 }; // ids of all users to display
 string[] userNameList = new []{ "Farix", "Doubles", "Rogue", "Splinter" }; // names of all users to display

您可以这样做:
 Array.Sort(userNameList, userIdList);

然后您将得到与LINQ代码完全相同的结果,但使用更简单的表达式,不像LINQ代码那样分配新数组,而只是重新排序现有数组中的项目,这更有效率。


这就是为什么我提供了整体的情况说明,而不仅仅指出我遇到困难的地方。 :) - Alexander
好的做法 :) 如果你只是贴出了LINQ代码而没有解释,那么理解你的意图会更困难。 - Faris Zacina

1

我想要类似于Scala的unzip()的功能,所以我使用了@zafar的解决方案

public static class ListExtensions
{
    public static (IEnumerable<T1>, IEnumerable<T2>) Unzip<T1, T2>(
        this IEnumerable<(T1, T2)> source
    ) => source.Unzip(tp => tp.Item1, tp => tp.Item2);

    public static (IEnumerable<T1>, IEnumerable<T2>) Unzip<T1, T2>(
        this IEnumerable<(T1, T2)> source,
        Func<(T1, T2), T1> f1,
        Func<(T1, T2), T2> f2
    ) => (source.Select(f1), source.Select(f2));
}

我点赞了这个答案,因为它是所有给出的风格中最实用的;然而在我的实现中,我使用了两个收集器列表来折叠列表,并直接从函数中返回它们,因为现在不推荐使用out变量。折叠的方法还消除了在第二个函数中迭代集合两次的问题。 - undefined
@StanleyG. 谢谢!我很久没写这个了,可能还有改进的空间,如果能用更少的迭代来实现同样的效果,请随时提出修改建议。 - undefined

1
如果集合是列表类型,您可以进行解压缩。 您可以编写自己的解压缩扩展方法来实现此目的:
 public static class ListExtensions
    {
        public static void Unzip<T, T1, T2>(this IList<T> source, Func<T, T1> firstSelector, Func<T, T2> secondSelector,
            out IEnumerable<T1> first, out IEnumerable<T2> second)
        {
            first = source.Select(firstSelector);
            second = source.Select(secondSelector);
        }
    }

使用方法:

enumerableEntitiesToUnzip.ToList().Unzip(e=>e.Prop1,e=>e.Prop2, out var first, out var second)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接