'Sort a List in Dart based on how another List was sorted

I am trying to sort a list with reference to another list. Consider this example,

List<String> a = ["a", "b", "c"];
List<int> b = [2, 3, 1];

Now, I want the result to be like this,

a = ["c", "a", "b"];
b = [1, 2, 3];

How can I achieve this result?



Solution 1:[1]

You can achieve this by create a Map that holds the mappings for the letters to your numbers, i.e. 2 has a assigned to it, 3 has b etc.
Now you can sort your list normally and after that recreate your other list based on the mappings that you stored before sorting:

main() {
  List<String> letters = ["a", "b", "c"];
  final List<int> numbers = [2, 3, 1];

  final Map<int, String> mappings = {
    for (int i = 0; i < numbers.length; i++)
      numbers[i]: letters[i]
  };

  numbers.sort();

  letters = [
    for (int number in numbers) mappings[number]
  ];

  print(letters); // [c, a, b]
  print(numbers); // [1, 2, 3]
}

I used collection for for this example. This syntax for collection literals was introduced in Dart 2.3.
Learn more.

You can easily turn this about and map the numbers to your letters instead. That would look like this:

main() {
  final List<String> letters = ["a", "b", "c"];
  List<int> numbers = [2, 3, 1];

  final Map<String, int> mapping = {
    for (int i = 0; i < letters.length; i++)
      letters[i]: numbers[i]
  };

  letters.sort((a, b) => b.compareTo(a));

  numbers = [
    for (String letter in letters) mapping[letter]
  ];

  print(letters); // [c, b, a]
  print(numbers); // [1, 3, 2]
}

Note that I sorted the letters in a descending order here by turning about the compareTo as well (by default a.compareTo(b) is used by List.sort).

Solution 2:[2]

If your Lists have duplicate elements, you won't be able to use a Map. I'd instead use package:tuple and then use the same approach of combining the two Lists into a single List<Tuple2>, sorting that, and extracting the values:

import 'package:tuple/tuple.dart';

void main() {
  var a = ["a", "b", "c", "d"];
  var b = [2, 3, 1, 1];

  var combined = <Tuple2<int, String>>[
    for (var i = 0; i < b.length; i += 1) Tuple2(b[i], a[i]),
  ];

  combined.sort((tuple1, tuple2) => tuple1.item1.compareTo(tuple2.item1));

  for (var i = 0; i < combined.length; i += 1) {
    a[i] = combined[i].item2;
    b[i] = combined[i].item1;
  }

  print(a); // Prints: [c, d, a, b]
  print(b); // Prints: [1, 1, 2, 3]
}

Solution 3:[3]

I use this way to solve the problem:

    List<String> strings = ["a", "b", "c", "c"];
    List<int> numbers = [2, 3, 1, 0];
    List<int> storeNumbers = List.from(numbers);
    List<int> storeIndex = [];
//sorting numbers list
 numbers.sort((a, b) => a.compareTo(b));

 //get the index of numbers list elements before the sorting
 for (int i = 0; i < numbers.length; i++) {
      for (int j = 0; j < storeNumbers.length; j++) {
        if (numbers[i] == storeNumbers[j]) {
                     storeIndex.add(j);
        }
      }
    }
    
    //generate a new string list based on the indexes we get
    strings =
        List.generate(strings.length, (index) => strings[storeIndex[index]]);

    print(strings);//output:[c, c, a, b]
    print(numbers);//output:[0, 1, 2, 3]

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 Jaafar Melhem