2010-11-29 5 views
3

У меня есть то, что кажется простой проблемой, но пока не могу понять.Сортировка двух массивов (значений, ключей), а затем сортировка ключей

Скажем, у меня есть два массива:

int[] values = {10,20,20,10,30}; 
int[] keys = {1,2,3,4,5}; 

Array.Sort(values,keys); 

Тогда массивы будут выглядеть следующим образом:

values = {10,10,20,20,30}; 
keys = {4,1,2,3,5}; 

Теперь, что я хочу сделать, это сделать так, что ключи также сортируются в второй приоритет, так что массив ключей будет выглядеть так:

keys = {1,4,2,3,5}; 

Обратите внимание, что значения 1 и 4 переключаются и порядок o f массив значений не изменился.

ответ

6

Если «на месте сортировки» не является строго необходимым для вас, я предлагаю использовать OrderBy:

var sortedPairs = values.Select((x, i) => new { Value = x, Key = keys[i] }) 
         .OrderBy(x => x.Value) 
         .ThenBy(x => x.Key) 
         .ToArray(); // this avoids sorting 2 times... 
int[] sortedValues = sortedPairs.Select(x => x.Value).ToArray(); 
int[] sortedKeys = sortedPairs.Select(x => x.Key).ToArray(); 

// Result: 
// sortedValues = {10,10,20,20,30}; 
// sortedKeys = {1,4,2,3,5}; 
+0

+1 LINQ на помощь – bitxwise 2010-11-29 22:55:32

1

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

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

1

Array.Sort (значения, ключи) будет использовать Comparer по умолчанию для сортировки значений и ключей. Вам нужно будет написать пользовательский Comparer, чтобы делать то, что вы описываете, и передать свой Comparer в метод Array.Sort.

0

Конвертируя это в сортировку по массиву пар значений, вы можете предоставить свой собственный компаратор и сделать сортировку практически любой, как вам нравится. (Кажется ужасным рискованным использовать два отдельных массива.) См. Четвертый метод: http://msdn.microsoft.com/en-us/library/system.array.sort.aspx.

0

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

Еще лучше объявить именованный тип для хранения данных все время. Параллельные массивы обычно не являются хорошей идеей. Существуют некоторые нишевые сценарии, в которых они необходимы для повышения производительности или взаимодействия, но в противном случае их следует избегать.

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

Например:

static void Main(string[] args) 
{ 
    int[] values = { 10, 20, 20, 10, 30 }; 
    int[] keys = { 1, 2, 3, 4, 5 }; 

    int[] indexes = Enumerable.Range(0, values.Length).ToArray(); 

    Array.Sort(indexes, (i1, i2) => Compare(i1, i2, values, keys)); 

    // Use the index array directly to access the original data 
    for (int i = 0; i < values.Length; i++) 
    { 
     Console.WriteLine("{0}: {1}", values[indexes[i]], keys[indexes[i]]); 
    } 

    Console.WriteLine(); 

    // Or go ahead and copy the old data into new arrays using the new order 
    values = OrderArray(values, indexes); 
    keys = OrderArray(keys, indexes); 

    for (int i = 0; i < values.Length; i++) 
    { 
     Console.WriteLine("{0}: {1}", values[i], keys[i]); 
    } 
} 

private static int Compare(int i1, int i2, int[] values, int[] keys) 
{ 
    int result = values[i1].CompareTo(values[i2]); 

    if (result == 0) 
    { 
     result = keys[i1].CompareTo(keys[i2]); 
    } 

    return result; 
} 

private static int[] OrderArray(int[] values, int[] indexes) 
{ 
    int[] result = new int[values.Length]; 

    for (int i = 0; i < values.Length; i++) 
    { 
     result[i] = values[indexes[i]]; 
    } 

    return result; 
} 
Смежные вопросы