用于将多个部分字符串列表与主要字符串进行比较的模式

时间:2012-06-14 23:54:41

标签: c# list design-patterns comparison

所以我有一个'超级'列表:DestinationColumn,有100个字符串。简而言之,总是100,

它来自几个源列,ColA,ColB。其中一些将有100个字符串,有些会少一些。

所以,例如:

ColA具有字符串1-33,40-70和90-100的值。它具有第一优先级,并将所有值填入DestinationColumn中以获取这些字符串。 ColB的值为1-40和70-100。如果存在间隙,则填充它,但它不能覆盖ColA字符串。

现在我想确保发生这种情况。

列出sourceColA,列出sourceColB 和ListdestinationColumn。

首先,我编写了一个函数来比较两个列表,看它们是否包含相同的字符串:

public static bool ListEquals<T>(IList<T> list1, IList<T> list2)
    {
        if ((list1 == null) || (list2 == null))
        {
            return false;
        }
        if (list1.Count != list2.Count)
            return false;
        for (int i = list1.Count - 1; i >= 0; --i)
        {
            if (!list1[i].Equals(list2[i]))
            {
                return false;
            }
        }
        return true;
    }

现在我想保持它的通用性,但是需要x源列,并确保所有内容现在都在一个目标列中正确。这样做有一般的模式吗?

我当前的想法是一个循环,将所有ColA的条目标记为destinationCol,重复B,依此类推,然后确保所有条目都不会被击中两次并且所有条目都被击中一次。

2 个答案:

答案 0 :(得分:1)

要按照您的描述合并两列,您可以像

一样进行
ColA.Zip(ColB, (a, b) => a??b)

所以:

void Main()
{
    IEnumerable<IEnumerable<string>> cols=
        new string[][]
        {
            new string[]{"monkey", "frog", null, null, null, null},
            new string[]{null, null, null, null, "cat", "giraffe"},
            new string[]{null, null, null, "dog", "fish", null}
        };
    cols.MergeLeft().Dump();
    //gives: "monkey", "frog", null, "dog", "cat", "giraffe" 


}

static class Ex
{
    public static IEnumerable<T> MergeLeft<T>
        (this IEnumerable<IEnumerable<T>> cols) where T:class
    {
        var maxItems = cols.Max(x => x.Count());
        var leftMerged = 
            cols
                .Aggregate(
                    Enumerable.Repeat((T)null, maxItems),
                    (acc,col) => acc.Zip(col, (a, b) => a ?? b));
        return leftMerged;

    }
}

修改

这是MergeLeft更有效的版本,不需要maxItems消除@Enigmativity下面描述的费用:

static class Ex
{
    public static IEnumerable<T> MergeLeft<T>
        (this IEnumerable<IEnumerable<T>> cols) where T:class
    {
        return cols
            .Aggregate(
                Enumerable.Empty<T>(),
                (acc,col) => 
                acc
                    .Concat(Infinite<T>(null))
                    .Zip(col, (a, b) => a ?? b));   
    }
    private static IEnumerable<T> Infinite<T>(T item)
    {
        for(;;){yield return item;}
    }
}

答案 1 :(得分:0)

我不完全确定我明白你要做什么,因为我不明白你的ListEquals的目的。无论如何,我会这样走:

    public static void FillDest<T>(IList<T> dest, IList<IList<T>> srcLists)
        where T : class
    {
        bool goon = true;
        int idx = 0;
        dest.Clear();
        while (goon)
        {
            goon = false;
            bool added = true;
            foreach (IList<T> aSrc in srcLists)
            {
                added = false;
                T anItem;
                if (aSrc.Count <= idx)
                {
                    added = true;
                    continue;
                }
                goon = true;
                if ((anItem = aSrc[idx]) != null)
                {
                    dest.Add(anItem);
                    added = true;
                    break;
                }
            }
            if (!added)
                dest.Add((T)null);
            idx++;
        }
    }