如何将两个List <string>合并为一个List <keyvaluepair>,包括空白?</keyvaluepair> </string>

时间:2014-08-16 17:10:54

标签: c#

我有两个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循环,并在我去的时候覆盖每个值。虽然这些列表是分开的,但它们是相互关联的(因此我加入它们的原因)。

4 个答案:

答案 0 :(得分:1)

这是ZipAllEnumerable.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);

小提琴:https://dotnetfiddle.net/INhbdg

答案 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));
    }
}