Warm tip: This article is reproduced from serverfault.com, please click

How to sort an array with respect to another array if there are duplicates?

发布于 2020-11-29 15:07:00

I could sort an array with respect to another if there is unique value. But since i am trying sort the below given array:

initial fuel[]={1,9,9,2,9,9};
initial cost[]={2,6,5,4,3,1};

I wanted to sort fuel array then again wanted to sort cost array with respect to fuel array.
I wanted output like given below:

final fuel[]={1,2,9,9,9,9};
final cost[]={2,4,6,5,3,1};

Below is my code:

public static void sort(List<Integer> c, List<Integer> f) {
    List<Integer> cc = new ArrayList<>(c);
    Collections.sort(c);

    List<Integer> al = new ArrayList<>();

    int i = 0;
    while (i < c.size()) {
        int temp = c.get(i);
        int index = cc.indexOf(temp);
        al.add(f.get(index));

        cc.remove(index);
        f.remove(index);

        i++;
    }

    for (int value : c)
        System.out.print(value + " ");
    System.out.println();
    for (int value : al)
        System.out.print(value + " ");
}

How can I use comparator to sort in this ways? Also how to use stream api for the same?

Questioner
Khushtar Hussain
Viewed
0
WJS 2020-11-30 02:45:55

If you always want to associate a given fuel value with cost then I suggest you create a class to hold them. This will allow proper sorting while keeping both values together.

int[] fuel = { 1, 9, 9, 2, 9, 9 };
int[] cost = { 2, 6, 5, 4, 3, 1 };

This creates the class and sorts it based on the fuel value, and puts it in a list.

List<FuelInfo> fuelInfo =
        // generate array indices
        IntStream.range(0, fuel.length)
        
        // create the objects 
        .mapToObj(i -> new FuelInfo(fuel[i], cost[i]))

        // sort them based on fuel value 
        .sorted(Comparator.comparing(FuelInfo::getFuel))

        // put them in a list.
        .collect(Collectors.toList());

 
fuelInfo.forEach(System.out::println)

Prints

[1, 2]
[2, 4]
[9, 6]
[9, 5]
[9, 3]
[9, 1]

You can copy the individual values back to a list as followis:

List<Integer> fuelList = fuelInfo.stream()
        .map(FuelInfo::getFuel).collect(Collectors.toList());
List<Integer> costList = fuelInfo.stream()
        .map(FuelInfo::getCost).collect(Collectors.toList());

If you want to maintain the default order for duplicates then this will work since the sorting in Java is stable (insertion order is maintained when comparing equals values). This works by using sorting the indices based on the value of the fuel array and then using the sorted indices to build the cost list in properly sorted order.

Comparator<Integer> comp = (a,b)->Integer.compare(fuel[a],fuel[b]);

Comparator<Integer> comp =
        (a, b) -> Integer.compare(fuel[a], fuel[b]);

List<Integer> sortedFuel = Arrays.stream(fuel).sorted()
        .boxed().collect(Collectors.toList());

List<Integer> sortedCost = IntStream.range(0, fuel.length)
        .boxed().sorted(comp).map(a -> cost[a])
        .collect(Collectors.toList());

System.out.println(sortedFuel);
System.out.println(sortedCost);

Prints

[1, 2, 9, 9, 9, 9]
[2, 4, 6, 5, 3, 1]

The FuelInfo class


class FuelInfo{
    private int fuelAmt;
    private int cost;
    public FuelInfo(int fuel, int cost) {
        this.fuelAmt = fuel;
        this.cost = cost;
    }
    public int getFuel() {
        return fuelAmt;
    }
    public int getCost() {
        return cost;
    }
    public String toString() {
        return String.format("[%s, %s]", fuelAmt, cost);
    }
}