拆分每个数字序列上的数字列表

时间:2018-05-02 16:01:58

标签: c# wpf list recursion

我一直在研究这个问题几天,我似乎无法得到我想要的确切结果。我已将我的问题简化为基于数字,以便我能够尽可能清楚地知道我在做什么以及我想要什么。

我从一个较大的List<List<double>>开始,其中较大的List中的每个子List包含3个数字。例如,List看起来像这样:

[0] 1,2,3

[1] 1,2,3

[2] 1,2,3

[3] 4,5,6

[4] 4,5,6

[5] 4,5,6

[6] 7,8,9

[7] 7,8,9

[8] 7,8,9

其中列表中的每个项目都是不同的序列。我想要完成的是将List分成一组较小的列表,其中列表中的每个项目都是相似的。所以对于给定的例子:

list1的:

[0] 1,2,3

[1] 1,2,3

[2] 1,2,3

清单2:

[0] 4,5,6

[1] 4,5,6

[2] 4,5,6

列表3:

[0] 7,8,9

[1] 7,8,9

[2] 7,8,9

因此,为了解决我的问题,我创建了一个函数来递归搜索List并提取相似的序列并将它们添加到单独的列表中。我的功能不仅不起作用,而且我的代码非常冗长和复杂,我觉得应该有类似的解决方案而不是我想做的。任何建议或建议让我朝着正确的方向前进,我们将不胜感激。

4 个答案:

答案 0 :(得分:1)

我认为这会为你做到。它适用于您的故障&#39;要求 - 即{1,2,3}等于{3,2,1}等于{2,3,1}。

static void Main(string[] args)
{
    List<List<double>> list = new List<List<double>>()
    {
        new List<double>() { 1,2,3 },
        new List<double>() { 4,5,6 },
        new List<double>() { 7,8,9 },

        new List<double>() { 2,3,1 },
        new List<double>() { 5,6,4 },
        new List<double>() { 8,9,7 },

        new List<double>() { 3,1,2 },
        new List<double>() { 6,4,5 },
        new List<double>() { 9,7,8 },
    };

    // Pick a method, they both work
    //var q2 = DictionaryMethod(list);
    var q2 = LinqAggregateMethod(list);

    foreach (var item in q2)
    {
        Console.WriteLine("List:");
        foreach (var item2 in item)
            Console.WriteLine($"\t{item2[0]}, {item2[1]}, {item2[2]}");
    }
}

static bool ListsAreEqual(List<double> x, List<double> y)
{
    foreach (var d in x.Distinct())
    {
        if (x.Count(i => i == d) != y.Count(i => i == d))
            return false;
    }
    return true;
}

static IEnumerable<IEnumerable<List<double>>> LinqAggregateMethod(List<List<double>> list)
{
    var q = list.Aggregate(new List<List<double>>() /* accumulator(ret) initial value */, (ret, dlist) =>
    {
        // ret = accumulator
        // dlist = one of the List<double> from list

        // If accumulator doesn't already contain dlist (or it's equal), add it
        if (!ret.Any(dlistRet => ListsAreEqual(dlist, dlistRet)))
            ret.Add(dlist);
        return ret;
    });
    // At this point, q contains one 'version' of each list.

    // foreach item in q, select all the items in list where the lists are equal
    var q2 = q.Select(dlist => list.Where(item => ListsAreEqual(dlist, item)));
    return q2;
}

static IEnumerable<IEnumerable<List<double>>> DictionaryMethod(List<List<double>> list)
{
    var list2 = new Dictionary<List<double>, List<List<double>>>();
    // Loop over each List<double> in list
    foreach (var item in list)
    {
        // Does the dictionary have a key that is equal to this item?
        var key = list2.Keys.FirstOrDefault(k => ListsAreEqual(k, item));
        if (key == null)
        {
            // No key found, add it
            list2[item] = new List<List<double>>();
        }
        else
        {
            // Key was found, add item to its value
            list2[key].Add(item);
        }
    }
    var q2 = new List<List<List<double>>>();
    foreach (var key in list2.Keys)
    {
        var a = new List<List<double>>();
        a.Add(key); // Add the key
        a.AddRange(list2[key]); // Add the other lists
        q2.Add(a);
    }
    return q2;
}

答案 1 :(得分:1)

以下是解决此问题的另一种方法。我将它分为两​​步。

public override void ViewWillAppear(bool animated)
{
    base.ViewWillAppear(animated);

    (ViewModel as UserCoinViewModel).LoadDataCommand.Execute(null);
    // You can also bind a button to this command to trigger it manually.
}

1)从您的收藏中获取所有唯一列表。您可以使用// Sample input: List<List<double>> lists = new List<List<double>>(); lists.Add(new List<double> { 1, 1, 3 }); lists.Add(new List<double> { 1, 3, 1 }); lists.Add(new List<double> { 3, 1, 1 }); lists.Add(new List<double> { 4, 5, 6 }); lists.Add(new List<double> { 4, 5, 6 }); lists.Add(new List<double> { 6, 5, 4 }); lists.Add(new List<double> { 7, 8, 9 }); lists.Add(new List<double> { 8, 7, 9 }); lists.Add(new List<double> { 9, 8, 7 }); 暂时订购它们。这样可以使用SequenceEqual进行比较:

OrderBy

2)现在,每个组都有一组代表。浏览每个代表并获取与您的代表中的元素相匹配的所有列表。在这里,您可以暂时订购它们,以便与List<List<double>> uniqueOrdered = new List<List<double>>(); foreach (var element in lists.Select(x => x.OrderBy(y => y).ToList())) { if (!uniqueOrdered.Any(x=> x.SequenceEqual(element))) { uniqueOrdered.Add(element); } }

进行比较
SequenceEqual

结果组中的列表将保持其原始顺序!

答案 2 :(得分:0)

我尽力缩短所需的代码来完成我想要完成的任务。顺便说一句,我将结果列表放在您将看到的列表中:

以下示例仅用于声明您的列表并放置随机值:

  List<List<int>> ContainerList = new List<List<int>>()
        {
            new List<int>()
            {
                0, 1, 2
            },
            new List<int>()
            {
                3, 4, 6
            },
            new List<int>()
            {
                0, 1, 2
            },
            new List<int>()
            {
                7, 8, 9
            },
        };

现在开始有效载荷:

        List<List<List<int>>> result = new List<List<List<int>>>();

        foreach (var cont in ContainerList)
            result.Add(ContainerList.FindAll(x => x.SequenceEqual(cont)));

        // the following erase duplicates
        result = result.Distinct().ToList();

所以现在你可以将你的子列表作为:

[0] [0] 012

[0] [1] 012

[1] [0] 346 ....

说明:

 ContainerList.FindAll(x => x.SequenceEqual(cont))

以下代码段使用谓词:此处的x是列表中的值。

由于它是一个列表列表,你的x将成为一个列表

SequenceEqual意味着Findall函数将按VALUE而不是REFERENCE搜索等式。

接下来我们擦除重复项,因为ContainerList的第一个元素上的Findall将返回一个列表,其中包含对应于给定参数(即x)的所有重复项。

但是随着参数(x)在列表中递增。您将执行尽可能多的FindAll,因为存在相同子集的值。所以在上面的例子中,你将有2个列表2 012;

我希望这是可以理解的。我的英语太可怕了。

答案 3 :(得分:0)

这是我将用于您给出的示例的代码。

    static void Main(string[] args)
{
    List<List<double>> lists = new List<List<double>>();
    lists.Add(new List<double> { 1, 2, 3 });
    lists.Add(new List<double> { 1, 2, 3 });
    lists.Add(new List<double> { 1, 2, 3 });
    lists.Add(new List<double> { 4, 5, 6 });
    lists.Add(new List<double> { 4, 5, 6 });
    lists.Add(new List<double> { 4, 5, 6 });
    lists.Add(new List<double> { 7, 8, 9 });
    lists.Add(new List<double> { 7, 8, 9 });
    lists.Add(new List<double> { 7, 8, 9 });
    lists.Add(new List<double> { 7, 8, 9 });

    List<List<List<double>>> sortedLists = new List<List<List<double>>>();

    for (int i = 0; i < lists.Count; i++)
    {
        bool found = false;
        if (!(sortedLists.Count == 0))
        {
            for (int j = 0; j < sortedLists.Count; j++)
            {
                if (lists[i][0] == sortedLists[j][0][0] && lists[i][1] == sortedLists[j][0][1] && lists[i][2] == sortedLists[j][0][2])
                {
                    found = true;
                    sortedLists[j].Add(lists[i]);
                    break;
                }
            }
        }
        if (!found)
        {
            sortedLists.Add(new List<List<double>> { lists[i] });
        }
    }
}

唯一的问题是内部if语句是专门为此示例设计的。

if (lists[i][0] == sortedLists[j][0][0] && lists[i][1] == sortedLists[j][0][1] && lists[i][2] == sortedLists[j][0][2])

如果您使用3个双重列表中的任何内容,则必须更改。