разбиение списка чисел на каждую последовательность чисел - PullRequest
0 голосов
/ 02 мая 2018

Я работаю над этой проблемой уже пару дней и, похоже, не могу получить именно тот результат, который ищу. Я упростил свой вопрос до числа, основанного на числе, чтобы я мог как можно яснее понять, что именно я делаю и что я хочу получить взамен.

Я начинаю с большого 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 на группу небольших списков, где все элементы в списке похожи. Итак, для приведенного примера:

песни1:

[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 голосов
/ 03 мая 2018

Вот еще один подход к этой проблеме. Я бы разделил его на 2 шага.

// 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 });

1) Получить все уникальные списки из вашей коллекции. Вы можете заказать их временно с OrderBy. Это позволит сравнивать, используя SequenceEqual :

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

2) Теперь у вас есть набор представителей для каждой из ваших групп. Пройдите через каждого представителя и получите все списки, которые соответствуют элементам вашего представителя. Опять же здесь вы можете временно заказать их для сравнения с SequenceEqual:

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

foreach (var element in uniqueOrdered)
{
    result.Add(lists.FindAll(x=> x.OrderBy(t=>t).SequenceEqual(element)));
}

Списки в результирующих группах сохранят свой первоначальный порядок!

0 голосов
/ 02 мая 2018

Это код, который я бы использовал для приведенного вами примера.

    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 двойных списков.

0 голосов
/ 03 мая 2018

Я думаю, что это сделает это для вас. Он работает с вашим требованием «не в порядке», то есть {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;
}
0 голосов
/ 02 мая 2018

Я изо всех сил старался сократить необходимый код, чтобы выполнить то, что, как я предполагаю, вы хотите выполнить. Кстати, я поместил полученные списки в список, который вы увидите:

этот следующий пример только для того, чтобы объявить ваш список и поместить случайные значения:

  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.

Далее мы удаляем дубликаты, потому что Findall в первом элементе ContainerList вернет список, содержащий все его дубликаты, соответствующие данному параметру (который равен x).

Но по мере увеличения параметра (x) в списке. Вы сделаете столько FindAll, сколько существует значений одного и того же подмножества. Таким образом, в приведенном выше примере у вас будет 2 списка по 2 012;

Надеюсь, это понятно. Мой английский ужасен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...