假设我有列表清单。我想从给定的列表列表中创建新列表,以便元素按照下面给出的示例顺序。
输入: -
List<List<int>> l = new List<List<int>>();
List<int> a = new List<int>();
a.Add(1);
a.Add(2);
a.Add(3);
a.Add(4);
List<int> b = new List<int>();
b.Add(11);
b.Add(12);
b.Add(13);
b.Add(14);
b.Add(15);
b.Add(16);
b.Add(17);
b.Add(18);
l.Add(a);
l.Add(b);
输出(列表): -
1
11
2
12
3
13
4
14
15
16
输出列表必须是not contain more than 10
个元素。
我目前正在使用foreach inside while
执行此操作,但我想知道如何使用LINQ
执行此操作。
int loopCounter = 0,index=0;
List<int> o=new List<int>();
while(o.Count<10)
{
foreach(List<int> x in l)
{
if(o.Count<10)
o.Add(x[index]);
}
index++;
}
感谢。
答案 0 :(得分:3)
使用接收项目索引的SelectMany
和Select
重载。这将用于应用所需的顺序。使用SelectMany
是为了展平嵌套集合级别。最后,应用Take
仅检索所需数量的项目:
var result = l.SelectMany((nested, index) =>
nested.Select((item, nestedIndex) => (index, nestedIndex, item)))
.OrderBy(i => i.nestedIndex)
.ThenBy(i => i.index)
.Select(i => i.item)
.Take(10);
或者在查询语法中:
var result = (from c in l.Select((nestedCollection, index) => (nestedCollection, index))
from i in c.nestedCollection.Select((item, index) => (item, index))
orderby i.index, c.index
select i.item).Take(10);
如果使用C#6.0和之前的项目,则使用匿名类型:
var result = l.SelectMany((nested, index) =>
nested.Select((item, nestedIndex) => new {index, nestedIndex, item}))
.OrderBy(i => i.nestedIndex)
.ThenBy(i => i.index)
.Select(i => i.item)
.Take(10);
解释为什么单独Zip
是不够的:zip相当于对第一个集合执行join
操作到第一个集合,其中
要加入的属性是索引。因此,只有第一个集合中存在的项目(如果它们在第二个集合中匹配)将显示在结果中。
下一个选项是考虑left join
,它将返回第一个集合的所有项目,并在第二个集合中匹配(如果存在)。在描述的情况下,OP正在寻找full outer join
的功能 - 尽可能获取收集和匹配的所有项目。
答案 1 :(得分:2)
我知道你要求LINQ,但我经常觉得LINQ是一个锤子,一旦开发人员发现它,每个问题都是钉子。为了可读性/可维护性的观点,我不会用LINQ完成这个,因为我觉得这样的事情更简单,更容易理解/更多自我记录:
List<int> r = new List<int>(10);
for(int i = 0; i < 10; i++){
if(i < a.Count)
r.Add(a[i]);
if(i < b.Count)
r.Add(b[i]);
}
如果a和b总共只有8个项目,你就不需要提前停止循环,但你可以通过扩展for循环的测试
我也认为这个案例可能比LINQ更具性能,因为它做得少很多
如果您使用LINQ的授权是学术性的(这是必须使用LINQ的作业),那么请继续,但如果它是一个普通的日常系统,其他一些可怜的傻瓜将不得不维持一天,我恳请你考虑这是否是一个很好的LINQ应用程序
答案 2 :(得分:0)
这将处理2个或更多内部List<List<int>>
- 它会通过IEnumerable<int>
返回yield
,因此您必须在其上调用.ToList()
才能进行此操作一个列表。 Linq.Any用于休息标准。
将抛出任何列表为null。根据自己的喜好添加支票。
static IEnumerable<int> FlattenZip (List<List<int>> ienum, int maxLength = int.MaxValue)
{
int done = 0;
int index = 0;
int yielded = 0;
while (yielded <= maxLength && ienum.Any (list => index < list.Count))
foreach (var l in ienum)
{
done++;
if (index < l.Count)
{
// this list is big enough, we will take one out
yielded++;
yield return l[index];
}
if (yielded > maxLength)
break; // we are done
if (done % (ienum.Count) == 0)
index += 1; // checked all lists, advancing index
}
}
public static void Main ()
{
// other testcases to consider:
// in total too few elememts
// one list empty (but not null)
// too many lists (11 for 10 elements)
var l1 = new List<int> { 1, 2, 3, 4 };
var l2 = new List<int> { 11, 12, 13, 14, 15, 16 };
var l3 = new List<int> { 21, 22, 23, 24, 25, 26 };
var l = new List<List<int>> { l1, l2, l3 };
var zipped = FlattenZip (l, 10);
Console.WriteLine (string.Join (", ", zipped));
Console.ReadLine ();
}