Java - Sort one array based on values of another array?

后端 未结 10 1750
不思量自难忘°
不思量自难忘° 2020-11-30 12:02

I have an array of Strings that are instances of a class from external code that I would rather not change.

I also have an array of ints that was generated by callin

相关标签:
10条回答
  • 2020-11-30 12:34

    Make a TreeMap<Integer, List<ObjectTypeFromA>> where the map key is the values in B, and the map values are the values in A (using a list to allow for duplicate keys). It will be sorted in the order of B by definition.

    public static void main(String[] args) {
      String[] strings = { "string1", "string2", "string3", "string4" };
      int[] ints = { 40, 32, 32, 34 };
      System.out.println(Arrays.toString(getSortedStringArray(strings, ints)));
    }
    
    public static String[] getSortedStringArray(String[] strings, int[] order) {
      Map<Integer, List<String>> map = new TreeMap<>();
      for (int i = 0; i < strings.length; i++) {
        if (!map.containsKey(order[i])) {
          map.put(order[i], new LinkedList<String>());
        }
        map.get(order[i]).add(strings[i]);
      }
      String[] ret = new String[strings.length];
      int i = 0;
      for (Map.Entry<Integer, List<String>> mapEntry : map.entrySet()) {
        for (String s : mapEntry.getValue()) {
          ret[i++] = s;
        }
      }
      return ret;
    }
    
    0 讨论(0)
  • 2020-11-30 12:35

    In java you need to have two arrays one copy to sort off and the array you want to sort.

    with a lambda:

    String[] strings = new String[]{"string1", "string2", "string3", "string4"};
    final int[] ints = new int[]{100, 88, 92, 98};
    
    final List<String> stringListCopy = Arrays.asList(strings);
    ArrayList<String> sortedList = new ArrayList(stringListCopy);
    Collections.sort(sortedList, (left, right) -> ints[stringListCopy.indexOf(left)] - ints[stringListCopy.indexOf(right)]);
    

    Or with Comparator:

    String[] strings = new String[]{"string1", "string2", "string3", "string4"};
    final int[] ints = new int[]{100, 92, 88, 98};
    
    final List<String> stringListCopy = Arrays.asList(strings);
    ArrayList<String> sortedList = new ArrayList(stringListCopy);
    Collections.sort(sortedList, Comparator.comparing(s -> ints[stringListCopy.indexOf(s)]));
    
    0 讨论(0)
  • 2020-11-30 12:36

    Short answer: I suggest that a separate class is created that holds the information about both the actual String and the boosting (the int). If you assume the following:

    public class BoostString {
        int boost;
        String str;
    
        public BoostString(int boost, String str) {
            this.boost = boost;
            this.str = str;
        }
    }
    

    Then, you can sort your array by using a Comparator and it works especially nice with the Java 8 Streaming API.

    String[] strings = {"string1", "string2", "string3"};
    int[] boosts = {40, 32, 34};
    
    final String[] sorted = IntStream.range(0, boosts.length)
            .mapToObj(i -> new BoostString(boosts[i], strings[i])) // Create the instance
            .sorted(Comparator.comparingInt(b -> b.boost))         // Sort using a Comparator
            .map(b -> b.str)                                       // Map it back to a string
            .toArray(String[]::new);                               // And return an array
    

    The Comparator in the example above is created using the Comparator.comparingInt method which is a convenient way of creating a Comparator for ints using Java 8.


    Explanation: Typically when comparing objects in Java you use one of the built-in sorting functions such as Collections.sort where you provide your own Comparator. The Comparator interface is straightforward and looks like this:

    public interface Comparator<T> {
        int compare(T o1, T o2);
    
        // Other default methods for Java 8
    }
    

    The return value is of type int and is described like this in the JavaDoc:

    return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.

    This works out-of-the-box when you are sorting Strings or int (or actually Integers) since they are Comparable – they sort of have a built-in natural sorting and for Strings this is in alphabetical order and for Integers this is sorted in ascending number order (see the JavaDoc for Comparable).

    On a side note, there are other "pair" or "tuple" implementations available if you are using 3rd party libraries. You do not have to create your own "pair" of a String and int. One example is the Pair class from Apache Commons.

    0 讨论(0)
  • 2020-11-30 12:38

    You can do something similar to your JS example in old style Java (but I would recommend joining your data together in an object as @wassgren suggests):

    import java.util.*;
    
    public class WeightSort {
      public static void main(String[] args) {
        String[] strings = new String[]{"string1", "string2", "string3"};
        final int[] weights = new int[]{40, 32, 34};
        final List<String> stringList = Arrays.asList(strings);
        List<String> sortedCopy = new ArrayList<String>(stringList);
        Collections.sort(sortedCopy, new Comparator<String>(){
            public int compare(String left, String right) {
              return weights[stringList.indexOf(left)] - weights[stringList.indexOf(right)];  
            }
          });
          System.out.println(sortedCopy);
      }
    }
    
    0 讨论(0)
提交回复
热议问题