Список вида C# на основе другого списка

У меня есть класс, который имеет несколько Список <> содержавший в нем. В основном таблица, хранимая с каждым столбцом как Список <>. Каждый столбец не содержит тот же тип. Каждый список является также той же длиной (имеет то же число элементов).

Например:

У меня есть 3 Списка <> объекты; один Список, два Списка и три Списка.

//Not syntactically correct
List<DateTime> one = new List...{4/12/2010, 4/9/2006, 4/13/2008};
List<double> two = new List...{24.5, 56.2, 47.4};
List<string> three = new List...{"B", "K", "Z"};

Я хочу смочь отсортировать список один от самых старых до новейших: один = {09.04.2006, 13.04.2008, 12.04.2010};

Таким образом, чтобы сделать это я переместил элемент 0 в конец.

Я затем хочу отсортировать список два и три тот же путь; перемещение первого к последнему.

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

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

6
задан John Gitzlsan 28 July 2010 в 18:01
поделиться

7 ответов

Раньше я занимался этим дизайном, сохраняя или создавая отдельный список индексов. Сначала вы сортируете список индекса, а затем используете его для сортировки (или просто доступа) к другим спискам. Вы можете сделать это, создав собственный IComparer для списка индексов. Что вы делаете внутри этого IComparer, так это сравнение на основе индексов в списке ключей. Другими словами, вы косвенно сортируете список индекса. Что-то вроде:

// This is the compare function for the separate *index* list.
int Compare (object x, object y)
{
  KeyList[(int) x].CompareTo(KeyList[(int) y])
}

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

7
ответ дан 8 December 2019 в 13:43
поделиться

Я написал алгоритм сортировки, который делает это для Nito.LINQ (еще не выпущен). Он использует простую QuickSort для сортировки списков и поддерживает синхронизацию любого количества связанных списков. Исходный код начинается здесь, в методе расширения IList .Sort .

В качестве альтернативы, если копирование данных не представляет большой проблемы, вы можете спроецировать его в запрос LINQ с помощью оператора Zip (требуется .NET 4.0 или Rx), упорядочить его, а затем извлечь каждый результат:

List<DateTime> one = ...;
List<double> two = ...;
List<string> three = ...;
var combined = one.Zip(two, (first, second) => new { first, second })
    .Zip(three, (pair, third) => new { pair.first, pair.second, third });
var ordered = combined.OrderBy(x => x.first);
var orderedOne = ordered.Select(x => x.first);
var orderedTwo = ordered.Select(x => x.second);
var orderedThree = ordered.Select(x => x.third);

Естественно, лучшее решение - в первую очередь не разделять связанные данные.

1
ответ дан 8 December 2019 в 13:43
поделиться

Сначала вы должны создать объект Data для хранения всего.

private class Data
{
    public DateTime DateTime { get; set; }
    public int Int32 { get; set; }
    public string String { get; set; }
}

Тогда вы можете отсортировать вот так.

var l = new List<Data>();
l.Sort(
    (a, b) =>
    {
        var r = a.DateTime.CompareTo(b);
        if (r == 0)
        {
            r = a.Int32.CompareTo(b);
            if (r == 0)
            {
                r = a.String.CompareTo(b);
            }
        }
        return r;
    }
);
2
ответ дан 8 December 2019 в 13:43
поделиться

Надеюсь, это может помочь:

one = one.Sort(delegate(DateTime d1, DateTime d2)
{
    return Convert.ToDateTime(d2).CompareTo(Convert.ToDateTime(d1));
});
0
ответ дан 8 December 2019 в 13:43
поделиться

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

{ 4/9/2006, 1 }, { 4/13/2008, 2 }, { 4/12/2010, 0 }

Второй набор операторов генерирует новые списки, выбирая элементы с помощью переупорядоченных индексов (другими словами, элементы 1, 2 и 0, в таком порядке).

var newOrdering = one
    .Select((dateTime, index) => new { dateTime, index })
    .OrderBy(item => item.dateTime)
    .ToArray();

// now, order each list
one = newOrdering.Select(item => one[item.index]).ToList();
two = newOrdering.Select(item => two[item.index]).ToList();
three = newOrdering.Select(item => three[item.index]).ToList();
3
ответ дан 8 December 2019 в 13:43
поделиться

Мне жаль, но это похоже на плохой дизайн. Особенно потому, что List не гарантирует порядок элементов до того, как вы вызовете одну из операций сортировки (поэтому у вас возникнут проблемы при вставке):

Из MSDN :

Список не гарантированно будет отсортировано. Вы должны отсортировать список перед выполнением операций (например, BinarySearch), которым требуется список быть отсортированным.

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

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

3
ответ дан 8 December 2019 в 13:43
поделиться

Использование универсальных массивов может стать немного громоздким.

Альтернативой является использование метода Array.Sort () , который принимает массив ключей и массив значений для сортировки. Сначала он сортирует массив ключей в порядке возрастания и обеспечивает реорганизацию массива значений в соответствии с этим порядком сортировки.

Если вы готовы взять на себя расходы по преобразованию ваших List s в массивы (а затем обратно), вы можете воспользоваться этим методом.

В качестве альтернативы вы можете использовать LINQ для объединения значений из нескольких массивов в один анонимный тип с помощью Zip () , отсортировать список анонимных типов с помощью ключевого поля, а затем разделить его на отдельные массивы.

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

1
ответ дан 8 December 2019 в 13:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: