LINQ - 合并2个列表但具有特定顺序

时间:2015-10-29 15:13:07

标签: c# linq list

我想将2个列表合并到一个列表中,但是,它必须按特殊顺序排列。

例如,我有一个类型A的列表:

{A,A,A,A,A,A ....}

还有一个B类清单:

{B,B,B,B ....}

期望的结果应该是这样的:

{A,A,B,A,A,B,A,A,B}

合并应该从列表A中获取2个项目,然后从列表B中获取1个项目。

有一点需要注意的是,如果一个列表变为空,请使用第二个列表的项填充所有其余项。

我试图用LINQ找到一种优雅的方式。

继承我的代码,但它有点长,我希望通过linq有更好的方法:

非常感谢。

    public IList<PersonBase> Order(IList<Person1> people1, IList<Person2> people2)
    {
        if (people1.IsNullOrEmpty())
            return people2;

        if (people2.IsNullOrEmpty())
            return people1;

        List<PersonBase> orderedList = new List<PersonBase>();

        var people1Count = 0;
        var people2Count = 0;

        while (people2Count < people2.Count || people1Count < people1.Count)
        {
            var people1ToAdd = tags.Skip(people1Count).Take(1).ToList();
            people1Count = people1.Count();
            orderedList.AddRange(people1ToAdd);

            if (people1Count >= people1.Count)
            {
                orderedList.AddRange(people2.Skip(people2Count));
                break;
            }

            var people2ToAdd = people2.Skip(peopleCount).Take(2).ToList();
            people2Count = people2.Count();
            orderedList.AddRange(people2ToAdd);

            if (people2Count >= people2.Count)
            {
                orderedList.AddRange(people1.Skip(people1Count));
                break;
            }
        }

        return orderedList;
    }

3 个答案:

答案 0 :(得分:1)

这是非常可怕的代码,但也做你想要的。基本上我们会跟踪每个列表索引并有一个int来跟踪用于填充结果数组的列表。

List<int> list1 = new List<int>() { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
List<int> list2 = new List<int>() { 2, 2, 2, 2, 2 };

int list1Counter = 0;
int list2Counter = 0;

int arraychecker = 1;

int[] resultArray = new int[list1.Count + list2.Count];
for (int i = 0; i < resultArray.Length; i++)
{
    if (list1Counter < list1.Count && list2Counter < list2.Count)
    {
        if (arraychecker == 1 || arraychecker == 2)
        {
            resultArray[i] = list1[list1Counter];
            list1Counter++;
            arraychecker++;
        }
        else
        {
            resultArray[i] = list2[list2Counter];
            list2Counter++;
            arraychecker = 1;
        }
    }
    else if (list1Counter < list1.Count)
    {
        resultArray[i] = list1[list1Counter];
        list1Counter++;
    }
    else
    {
        resultArray[i] = list2[list2Counter];
        list2Counter++;
    }
}

答案 1 :(得分:0)

您可以计算每个项目的索引,然后按该索引排序。

var mergedList =
    listA.Select((item, index) =>
        new { Index = index / 2 * 3 + (i % 2), Item = item})
    .Concat(listB.Select((item, index) =>
        new { Index = i * 3 + 2, Item = item}))
    .OrderBy(x => x.Index)
    .Select(x => x.Item)
    .ToList();

或者写一个方法。这样更有效,因为它不需要排序;它只会遍历每个列表一次。

static IEnumerable<T> Alternate<T>(IEnumerable<T> sourceA, IEnumerable<T> sourceB) {
    using (IEnumerator<T> eA = sourceA.GetEnumerator(), eB = sourceB.GetEnumerator()) {
        bool aHasItems = true, bHasItems = true; 
        while (aHasItems || bHasItems) {
            if (eA.MoveNext()) yield return eA.Current;
            if (aHasItems = eA.MoveNext()) yield return eA.Current;
            if (bHasItems = eB.MoveNext()) yield return eB.Current;
        }
    }
}

答案 2 :(得分:0)

这是我能做的最好的事情:

string[] test1 = { "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A" };
string[] test2 = { "B", "B" };
string[] result = test2.SelectMany((value, key) => test1.Skip(key * 2).Take(2).Concat(test2.Skip(key).Take(1))).ToArray();
        result = result.Concat(test1.Skip(result.Length / 3 * 2).Take(test1.Length - result.Length / 3 * 1)).ToArray();

这将从array1中获取2,然后从数组2中获取1,然后添加较长的一个的剩余部分。输出:

AABAABAAAAAAAAA