3

I have two arrays:

First array:
25, 20, 50, 30, 12, 11...

Second Array: 
New York, New Jersey, Detroit, Atlanta, Chicago, Los Angeles

Every two cities from the second array correspond to one value from the first.

Example: New York and New Jersey would correspond to 25, Detroit and Atlanta would correspond to 20 and so on.

I want to reorder the first Array's numbers in descending order (50, 30, 25, 20...), but I also want the cities of the second array to be shifted accordingly so that they have the same value before and after the sort.

How do I accomplish this task? (I can use either an ArrayList or an Array, whichever works out simpler)

PM 77-1
  • 12,933
  • 21
  • 68
  • 111
Sam
  • 129
  • 2
  • 10
  • 1
    http://stackoverflow.com/questions/12824423/sort-array-and-reflect-the-changes-in-another-array?lq=1 , http://stackoverflow.com/questions/112234/sorting-matched-arrays-in-java?lq=1 (unlike .NET, Java does not have standard library support for multi-array sorting) – user2864740 Dec 07 '15 at 03:00
  • Are the values in each array unique? – Caleb Brinkman Dec 07 '15 at 04:33
  • 1
    You might prefer using a Map in java for something like that. http://stackoverflow.com/questions/12824423/sort-array-and-reflect-the-changes-in-another-array?lq=1 http://stackoverflow.com/questions/109383/how-to-sort-a-mapkey-value-on-the-values-in-java – Naman Dec 07 '15 at 04:52

4 Answers4

1

You can use TreeMap:

Map<Integer, String[]> map = new TreeMap<>();
for(int i=0;i<firstArray.length;i++){
   map.put(firstArray[i], new String[]{secondArray[i * 2], secondArray[i*2+1]});
}

And this map will be sorted by key natural order.

But I would suggest you to make container class. Something like:

public class CityPair{
  public int value;
  public String[] cities = new String[2]; 
}

Now you can fill the list by your data:

...   
ArrayList list = new ArrayList<CityPair>();

for(int i=0; i<firstArray.length; i++){
  CityPair pair = new CityPair();
  pair.value = firstArray[i];
  pair.cities[0] = secondArray[i*2];
  pair.cities[1] = secondArray[i*2+1];
  list.add(pair);
}
...

As you see, I didn't check indexes for "index out of bounds", but you should. After that you can sort your list. You could do it manually using for example Bubble sort algorithm, but better way is write custom comparator:

public class CityPairComparator implements Comparator<CityPair> {
    @Override
    public int compare(CityPair pair1, CityPair pair2) {
        return Integer.compare(pair1.value, pair2.value);
    }
}

Now you can sort your list with Collections utility class:

Collections.sort(list, new CityPairComparator());

With this approch you can replace String[] cities in CityPair class for ArrayList<Sting> cities. Then it's will be able to add more than two cities per value.

Ken Bekov
  • 13,696
  • 3
  • 36
  • 44
1

Java 8 provides a slightly more elegant way to do this without needing a separate map:

int[] array1;
String[] array2;

array2 = IntStream.range(0, Math.min(array1, array2))
    .boxed().sorted(Comparator.comparingInt(i -> array1[i]))
    .map(i -> array2[i])
    .toArray(array2);

The boxing is only required because IntStream does not have a sorted method with a custom Comparator. I'm not sure why not.

If you want to end up with a List then use .collect(Collectors.toList()) instead of toArray.

sprinter
  • 27,148
  • 6
  • 47
  • 78
0

Here's a (4 line) solution that also handles mismatched array lengths:

int[] numbers = {25, 20, 50};
String[] cities = {"New York", "New Jersey", "Detroit", "Atlanta", "Chicago", "Los Angeles"};

Map<Object, Object> map = new TreeMap<>(Comparator.comparing(Integer.class::cast, Integer::compare).reversed());
for (Iterator<?> n = Arrays.stream(numbers).iterator(),
    s = Arrays.stream(String.join(",", cities).split(",(?=(([^,]*,){2})*[^,]*,[^,]*$)")).iterator();
    n.hasNext() && s.hasNext(); )
    map.put(n.next(), s.next());
numbers = map.keySet().stream().map(String::valueOf).mapToInt(Integer::parseInt).toArray();
cities = map.values().stream().map(String::valueOf).map(s -> s.split(",")).flatMap(Arrays::stream).toArray(String[]::new);

This creates two iterators on the fly from streams of each array, both typed to Object to allow dual initialization within the for loop. The cities array is first joined into one string then split into pairs-as-a-String (using an appropriate regex). The elements of both iterators populate a TreeMap, which has a reversed Integer comparator.

Because TreeMaps iterate in sorted order, a stream of keySet() and values() can be used to generate the resulting arrays.

The for loop's terminal condition checks both iterators to see if there's a next element available, which causes excess elements of the longer array to be ignored if the arrays aren't of equal length.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
0

I have tried a solution like this, It is using Arraylist as per your requirement :

First I have created a new data structure for your operation. As each value will hold two city name:

 public class Citizen implements Comparable<Citizen>  {

    private int citizenId;
    private String subjectOne;
    private String subjectTwo;


    public Citizen(int rollNumber, String subjectOne, String subjectTwo){
        this.citizenId = rollNumber;
        this.subjectOne = subjectOne;
        this.subjectTwo = subjectTwo;
    }

    public int getRollNumber() {
        return citizenId;
    }
    public void setRollNumber(int rollNumber) {
        this.citizenId = rollNumber;
    }
    public String getSubjectOne() {
        return subjectOne;
    }
    public void setSubjectOne(String subjectOne) {
        this.subjectOne = subjectOne;
    }
    public String getSubjectTwo() {
        return subjectTwo;
    }
    public void setSubjectTwo(String subjectTwo) {
        this.subjectTwo = subjectTwo;
    }


        public int compareTo(Citizen comparestu) {
            int compareage=((Citizen)comparestu).getRollNumber();
            /* For Ascending order*/
            return this.citizenId-compareage;

            /* For Descending order do like this */
            //return compareage-this.studentage;
        }

        @Override
        public String toString() {
            return "[ rollno=" + citizenId + ", subjectOne=" + subjectOne + ", subjectTwo=" + subjectTwo + "]";
        }   
}

As you can see here the parameter for comparison is taken as citizenID using implementation of Comparable interface.

now to call :

public static void main(String[] args) {

        ArrayList<Citizen> studentList = new ArrayList<Citizen>();

        studentList.add(new Citizen(25, "New York", "New Jersey"));
        studentList.add(new Citizen(20, "Detroit", "Atlanta"));
        studentList.add(new Citizen(50, "Chicago", "Los Angeles"));
        studentList.add(new Citizen(30, "Kolkata", "Delhi"));
        studentList.add(new Citizen(12, "Munmbai", "Baranasi"));
        studentList.add(new Citizen(11, "Bangalore", "Goa"));



        Collections.sort(studentList);
           for(Citizen student: studentList){
                System.out.println(student);
           }
    }

output :

[ rollno=11, subjectOne=Bangalore, subjectTwo=Goa]
[ rollno=12, subjectOne=Munmbai, subjectTwo=Baranasi]
[ rollno=20, subjectOne=Detroit, subjectTwo=Atlanta]
[ rollno=25, subjectOne=New York, subjectTwo=New Jersey]
[ rollno=30, subjectOne=Kolkata, subjectTwo=Delhi]
[ rollno=50, subjectOne=Chicago, subjectTwo=Los Angeles]
Sagiruddin Mondal
  • 5,407
  • 2
  • 29
  • 44