我有两个List对象要合并到一个List<KeyValuePair>
中。我知道Enumerable.Zip
,但如果第二个列表为空,则结果列表为空。如果第二个列表为空,我希望结果列表包含空格。例如,如果列表1有{"apple", "orange", "cherry"}
而列表2有{"", "", ""}
或没有元素,那么我希望结果列表为:
1)&#34; apple,&#34;&#34;
2)&#34; orange&#34;,&#34;&#34;
3)&#34; cherry&#34;,&#34;&#34;
我能想到的唯一方法就是在列表1(我的&#34;键&#34;在KeyValuePair
中)做一个foreach循环,在那里我用空值添加每个Key,然后在List 2上执行foreach循环,并在我去的时候覆盖每个值。虽然这些列表是分开的,但它们是相互关联的(因此我加入它们的原因)。
答案 0 :(得分:1)
这是ZipAll
,Enumerable.Zip
的版本,如果任一集合比另一集合短,则会返回任一集合类型的默认值。
public static class EnumerableEx
{
public static IEnumerable<TReturn> ZipAll<T1, T2, TReturn>(
this IEnumerable<T1> first,
IEnumerable<T2> second,
Func<T1, T2, TReturn> f,
T1 seed1,
T2 seed2)
{
var iter1 = first.GetEnumerator();
var iter2 = second.GetEnumerator();
while(iter1.MoveNext())
{
if(iter2.MoveNext())
yield return f(iter1.Current, iter2.Current);
else
yield return f(iter1.Current, seed2);
}
while(iter2.MoveNext())
yield return f(seed1, iter2.Current);
}
public static IEnumerable<TReturn> ZipAll<T1, T2, TReturn>(
this IEnumerable<T1> first,
IEnumerable<T2> second,
Func<T1, T2, TReturn> f)
{
return first.ZipAll(second, f, default(T1), default(T2));
}
}
用法:
//create KeyValuePairs + fill shorter list with empty strings
var zip = a.ZipAll(b, (x,y) => new KeyValuePair<string, string>(x,y), "", "");
//create tuples + fill with nulls
var zip = a.ZipAll(b, Tuple.Create);
答案 1 :(得分:1)
你可以推出自己的Zip方法。它可能看起来像这样:
public static class EnumerableExt
{
public static IEnumerable<TOut> ZipAll<TIn1, TIn2, TOut>(
this IEnumerable<TIn1> sequence1,
IEnumerable<TIn2> sequence2,
Func<TIn1, TIn2, TOut> combiner)
{
sequence1 = sequence1 ?? Enumerable.Empty<TIn1>();
sequence2 = sequence2 ?? Enumerable.Empty<TIn2>();
var seq1Enum = sequence1.GetEnumerator();
var seq2Enum = sequence2.GetEnumerator();
for(;;)
{
var hasMore1 = seq1Enum.MoveNext();
var hasMore2 = seq2Enum.MoveNext();
if(hasMore1 || hasMore2)
{
yield return combiner(
hasMore1 ? seq1Enum.Current : default(TIn1),
hasMore2 ? seq2Enum.Current : default(TIn2));
}
else
{
break;
}
}
}
}
你可以像这样使用它:
var a=new []{"hello", "world"};
var b=new string[]{};
var result = a.ZipAll(b,
(aa, bb) =>
new KeyValuePair<string,string>(
aa ?? string.Empty,
bb ?? string.Empty));
答案 2 :(得分:0)
如果您担心list2
短于list1
,那么您需要将空字符串附加到list2
以获取偶数长度列表的压缩:
list1
.Zip(
list2.Concat(Enumerable.Repeat("", list1.Count-list2.Count)),
(x, y) => new KeyValuePair<string, string>(x, y)
.ToList();
答案 3 :(得分:0)
您可以选择索引并加入索引。这将在它们的索引上左边连接两个枚举,如果找不到则允许传入默认值。这不仅仅是字符串。我添加了默认值,因为在您的示例中是字符串。 String的默认值为null,所以现在你可以传入String.Empty。
public static class ExtensionMethods
{
public static IEnumerable<KeyValuePair<TFirst, TSecond>> ZipJoin<TFirst, TSecond>(this IEnumerable<TFirst> first,
IEnumerable<TSecond> second)
{
return first.ZipJoin(second, default(TSecond));
}
public static IEnumerable<KeyValuePair<TFirst, TSecond>> ZipJoin<TFirst, TSecond>(this IEnumerable<TFirst> first,
IEnumerable<TSecond> second,
TSecond defaultValue)
{
return (from l1 in first.Select((item, index) => new KeyValuePair<int, TFirst>(index, item))
join l2 in second.Select((item, index) => new KeyValuePair<int, TSecond>(index, item)) on l1.Key
equals l2.Key into l2Group
from l3 in l2Group.DefaultIfEmpty(new KeyValuePair<int, TSecond>(0, defaultValue))
select new KeyValuePair<TFirst, TSecond>(l1.Value, l3.Value));
}
}