如何合并两个ListKeyValuePair>包括空格

本文关键字:string KeyValuePair 空格 包括 List 何合并 合并 两个 | 更新日期: 2023-09-27 18:18:21

我有两个List对象,我想合并为一个List<KeyValuePair>。我知道Enumerable.Zip,但如果第二个列表为空,则结果列表为空。如果第二个List为空,我希望生成的List包含空格。例如,如果列表1有{"apple", "orange", "cherry"},列表2有{"", "", ""}或没有元素,那么我希望结果列表为:

1)"苹果"、"
2)"橙色"、"
3)"樱桃"、"

我能想到的唯一方法是在列表1 (KeyValuePair中的"keys")上执行foreach循环,其中我用空白值添加每个Key,然后在列表2上执行foreach循环并覆盖每个值。虽然这些列表是独立的,但它们意味着彼此关联(因此我将它们合并在一起)。

如何合并两个List<string>KeyValuePair>包括空格

您可以使用自己的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));

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

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

如果您担心list2list1短,那么您需要将空字符串附加到list2以获得跨越偶数长度列表的zip:

list1
    .Zip(
        list2.Concat(Enumerable.Repeat("", list1.Count-list2.Count)),
        (x, y) => new KeyValuePair<string, string>(x, y)
    .ToList();

您可以使用索引选择out并连接它们的索引。这将在它们的索引上左连接两个枚举,允许在没有找到的情况下传递默认值。这不仅仅适用于字符串。我添加了默认值,因为在您的示例中是字符串。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));
    }
}