Разделение списка чисел на каждую последовательность чисел

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

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

«каждый список содержит 3 числа» <= Что это значит? Сто двадцать три - это одно число. 123. Вы действительно намеревались иметь 3 числа? 1,2,3? Или это диапазон чисел от 100 до 999?

P.Brian.Mackey 02.05.2018 18:08

последний: 1,2,3

Stavros 02.05.2018 18:10

В таком случае я не понимаю вопроса. Что больше? 1,2,3 или 1,3,2? Почему?

P.Brian.Mackey 02.05.2018 18:11

порядок чисел не имеет значения, если последовательность содержит одинаковые числа.

Stavros 02.05.2018 18:13

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

Mong Zhu 02.05.2018 18:19

1,2,3 похож на 3,2,1, войдут ли они в одну группу?

Mong Zhu 02.05.2018 18:20

@MongZhu, да. 1,2,3 и 3,2,1 будут в одной группе. 1,2,4 и 3,2,1 будут разными группами

Stavros 02.05.2018 18:25

Разрешены отрицательные числа?

P.Brian.Mackey 02.05.2018 18:27

«Да. 1,2,3 и 3,2,1 будут в одной группе», как вы можете видеть, это жизненно важная информация. Вы должны включить это в свой пост. В противном случае вы получите ответы, которые не решат вашу проблему точно.

Mong Zhu 02.05.2018 18:46
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
9
83
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

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

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

  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;

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

SequenceEqual, к сожалению, не распознает 1,2,3 и 3,2,1 как принадлежащие к одной группе.
Mong Zhu 02.05.2018 18:34

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

Mong Zhu 02.05.2018 18:37

Это правда, я не видел, что требуется нарушение порядка, кстати, мы можем просто изменить последовательность, равную лямбде, которая проверяет первую и вторую последовательность в соответствии с предварительным условием. А для Distinct правильное использование Except должно работать нормально. И это намного проще, чем другие коды, поскольку для этого требуется всего несколько строк.

Gaby 03.05.2018 10:08

да, для Distinct нужен IEqualityComparer, который нужно либо реализовать, либо использовать с HashSet<T>. Как получить уникальные предметы, используя Except? мне интересно

Mong Zhu 03.05.2018 10:16

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

    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])

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

OP написал этот комментарий выше: «Да. 1,2,3 и 3,2,1 будут в одной группе», оператор if в вашем сообщении не может это объяснить. Эти числа распределяются по разным группам.

Mong Zhu 03.05.2018 08:43
Ответ принят как подходящий

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

браво, единственное рабочее решение здесь :)

Mong Zhu 03.05.2018 08:45

Вот еще один подход к этой проблеме. Я бы разделил это на 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. Это позволит провести сравнение с использованием Последовательность: равно:

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

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

Другие вопросы по теме