4

I have two arrays, one stores the distance of the cities and the other stores the corresponding population. Everything works fine if the distance of the cities is in ascending order. But let say if someone inputs the distance randomly. How can I sort the cities array and also make sure that the population of the respective city is in the same index as the index of its respective city population.

For example:

  • City 1 has population 333
  • City 3 has population 33333
  • City 5 has population 33
int[] city = {1, 3, 5};
int[] pop  = {333, 33333, 33};

Everything works fine because the city array is sorted already.

But when I input:

int[] city = {3, 1, 5};
int[] pop  = {3333, 333, 33};

Big problem!

I want sort the array city and make sure that the population array has all its elements at the same index as their respective city.

2
  • 8
    As they are related information, maybe it is a good idea to store both information on a City Object. Commented Apr 6, 2016 at 2:42
  • The solution to your problem is exactly what @marcellorvalle says. Sorting one array of objects is immensely simpler and a lot less error-prone than sorting two arrays and always keeping them in sync. Anti-pattern: parallel collections Commented Oct 23, 2024 at 3:32

6 Answers 6

10

The good way of doing this is having a city class:

class City{
    private int id;
    private long population;

    //... getters, setters, etc
}

a city comparator class:

class CityPopulationComparator implements Comparator<City> {
    @Override
    public int compare(City c1, City c2) {
        return Long.compare(c1.getPopulation(), c2.getPopulation());
    }
}

And an array list of cities:

ArrayList<City> cities;

and finally sort it using:

Collections.sort(cities, new CityPopulationComparator());

But if you need to have your cities and populations this way, you can write a sort method yourself (a bubble sort for example) and whenever you swap two cities, also swap corresponding pupulations.

Sign up to request clarification or add additional context in comments.

6 Comments

The City class can even implement Comparable<City> as an alternative. This way, you can call Collections.sort with only the collection of cities.
Also, when dealing with sorting and collections, your object should override the equals() and hashCode() methods as well. This will make each object truly unique.
@Mr.Polywhirl Yes. and since I thought it isn't the "natural" ordering of City, I preferred the Comparator way.
@Mr.Polywhirl There will be many ways of sorting cities. I'm not sure sorting by population is more natural than sorting by id. That makes using a Comparator for the specific sort a good plan. I would have called it CityPopulationComparator.
@AliSeyedi: Does the order of ids matter if the population of two cities is equivalent?
|
4

The correct solution is this. However if you want a completely mad hack, you can do this:

public final class ParallelIntArrays extends AbstractList<int[]> {

    private final int[] array1;
    private final int[] array2;

    public ParallelIntArrays(int[] array1, int[] array2) {
        if (array1.length != array2.length)
            throw new IllegalArgumentException();
        this.array1 = array1;
        this.array2 = array2;
    }

    @Override
    public int[] get(int i) {
        return new int[] { array1[i], array2[i] };
    }

    @Override
    public int size() {
        return array1.length;
    }

    @Override
    public int[] set(int i, int[] a) {
        if (a.length != 2)
            throw new IllegalArgumentException();
        int[] b = get(i);
        array1[i] = a[0];
        array2[i] = a[1];
        return b;
    }
}

Then you can do:

int[] city = {5,   1,  2,    4,   3   };
int[] pop =  {100, 30, 4000, 400, 5000};
new ParallelIntArrays(city, pop).sort(Comparator.comparingInt(arr -> arr[0]));
System.out.println(Arrays.toString(city));
System.out.println(Arrays.toString(pop));

Note that as written above, ParallelIntArrays does not function correctly as a List. For example list.contains(list.get(0)) would give false. If you made it a List<IntBuffer> or a List<List<Integer>> instead, it would be fixed.

Comments

2

If your city id is unique:

int[] city = { 3,    1,   5};
int[] pop  = {3333, 333, 33};
Map<Integer, Integer> arr = new HashMap<>(city.length);
for (int i = 0; i < city.length; i++) {
    arr.put(city[i], pop[i]);
}
Arrays.sort(city);
for (int i = 0; i < city.length; i++) {
    pop[i] = arr.get(city[i]);
}

The same using SortedMap

int[] city = { 3,    1,   5};
int[] pop  = {3333, 333, 33};
SortedMap<Integer, Integer> arr = new TreeMap<>();
for (int i = 0; i < city.length; i++) {
    arr.put(city[i], pop[i]);
}
System.out.println(arr.keySet());
System.out.println(arr.values());

Comments

1

A "cheap" way would be to have a third array which would contain 0 to n representing the index of the other arrays

But the problem you are having would disappear if they were grouped in a class, both information seem logically related. Then you would implement Comparable: https://stackoverflow.com/a/18896422

Comments

0

You can collect a third array containing pairs of elements of these two arrays and sort it. Then you can iterate over this array and replace the elements of the first two arrays:

int[] city = {3, 1, 5};
int[] pop = {333, 33333, 33};

int[][] sorted = IntStream.range(0, city.length)
        // Stream<int[]>
        .mapToObj(i -> new int[]{city[i], pop[i]})
        // sort by city
        .sorted(Comparator.comparing(arr -> arr[0]))
        .toArray(int[][]::new);

// replace the elements of the first two arrays
IntStream.range(0, sorted.length).forEach(i -> {
    city[i] = sorted[i][0];
    pop[i] = sorted[i][1];
});

System.out.println(Arrays.toString(city)); // [1, 3, 5]
System.out.println(Arrays.toString(pop)); // [33333, 333, 33]

See also: How do I sort two arrays in relation to each other?

Comments

0
public static void main(String[] args) {
    Integer[] bidAmount = {3000, 54000, 2000, 1000, 5600};
    String[] bidderName = {"Jenny", "Mike", "Alvin", "Berry", "John"};
    Map<Integer, String> stringTreeMap = new TreeMap<>();
    stringTreeMap.put(bidAmount[0], bidderName[0]);
    stringTreeMap.put(bidAmount[1], bidderName[1]);
    stringTreeMap.put(bidAmount[2], bidderName[2]);
    stringTreeMap.put(bidAmount[3], bidderName[3]);
    stringTreeMap.put(bidAmount[4], bidderName[4]);

    for (Map.Entry<Integer, String> entry : stringTreeMap.entrySet()) {
        Integer key = entry.getKey();
        String value = entry.getValue();

        System.out.println(key + " => " + value);
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.