简体   繁体   中英

Sorting 2D array of strings in Java

I know that this question might have been asked before, but I was not able to find a fit answer. So say I have this array:

String[][] theArray = {
        {"james", "30.0"},
        {"joyce", "35.0"},
        {"frank", "3.0"},
        {"zach", "34.0"}};

Is there a way to descendingly sort this array by the second element of each sub-element. So I would get something like this.

theArray = {
        {"joyce", "35.0"},
        {"zach", "34.0"},
        {"james", "30.0"},
        {"frank", "3.0"}};

Use Arrays.sort(arr, comparator) with a custom comparator:

Arrays.sort(theArray, new Comparator<String[]>(){

    @Override
    public int compare(final String[] first, final String[] second){
        // here you should usually check that first and second
        // a) are not null and b) have at least two items
        // updated after comments: comparing Double, not Strings
        // makes more sense, thanks Bart Kiers
        return Double.valueOf(second[1]).compareTo(
            Double.valueOf(first[1])
        );
    }
});
System.out.println(Arrays.deepToString(theArray));

Output:

[[joyce, 35.0], [zach, 34.0], [james, 30.0], [frank, 23.0]]


Beware:

you will be sorting the array you passed in, Arrays.sort() will not return a new array (in fact it returns void). If you want a sorted copy, do this:

String[][] theCopy = Arrays.copyOf(theArray, theArray.length);

And perform the sorting on theCopy , not theArray .

You must use the Arrays.sort() method . This method takes a Comparator as argument. The sort method delegates to the comparator to determine if one element of the array must be considered bigger, smaller or equal to another element. Since every element of the outer array is an array, the comparator will have to compare arrays (of Strings).

The arrays must be compared based on the value of their second element. This second element is a String which in fact represents a double number. So you'll have to transorm the strings into numbers, else the order will be lexicographical (20 come before 3) rather than numerical.

The comparator could thus look like this :

public class StrinArrayComparator implements Comparator<String[]> {
    @Override
    public int compare(String[] array1, String[] array2) {
        // get the second element of each array, andtransform it into a Double
        Double d1 = Double.valueOf(array1.[1]);
        Double d2 = Double.valueOf(array2.[1]);
        // since you want a descending order, you need to negate the 
        // comparison of the double
        return -d1.compareTo(d2);
        // or : return d2.compareTo(d1);
    }
}

If you want to move away from arrays, here's a variation that uses List<Record> and a RecordComparator that implements Comparator<Record> .

Console:

joyce 35.0
zach 34.0
james 30.0
frank 23.0

Code:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/** @see http://stackoverflow.com/questions/5064027 */
public class ComparatorTest {
    public static void main(String[] args) {
        List<Record> list = new ArrayList<Record>(Arrays.asList(
            new Record("james", "30.0"),
            new Record("joyce", "35.0"),
            new Record("frank", "23.0"),
            new Record("zach",  "34.0")));
        print(list, Sort.DESCENDING, Field.D);
    }

    private static void print(List<Record> list, Sort s, Field f) {
        RecordComparator rc = new RecordComparator(s, f);
        Collections.sort(list, rc);
        for (Record r : list) {
            System.out.println(r);
        }
    }
}

class Record {

    private String s;
    private Double d;

    public Record(String name, String number) {
        this.s = name;
        this.d = Double.valueOf(number);
    }

    @Override
    public String toString() {
        return s + " " + d;
    }

    public int compareTo(Field field, Record record) {
        switch (field) {
            case S: return this.s.compareTo(record.s);
            case D: return this.d.compareTo(record.d);
            default: throw new IllegalArgumentException(
                "Unable to sort Records by " + field.getType());
        }
    }
}

enum Sort { ASCENDING, DESCENDING; }

enum Field {

    S(String.class), D(Double.class);

    private Class type;

    Field(Class<? extends Comparable> type) {
        this.type = type;
    }

    public Class getType() {
        return type;
    }
}

class RecordComparator implements Comparator<Record> {

    private Field field;
    private Sort sort;

    public RecordComparator(Sort sort, Field field) {
        this.sort = sort;
        this.field = field;
    }

    @Override
    public final int compare(Record a, Record b) {
        int result = a.compareTo(field, b);
        if (sort == Sort.ASCENDING) return result;
        else return -result;
    }
}

You seem to be living in object denial . Those inner arrays look a lot like information about a Person (with the name and some value, maybe a score).

What you'd want to do is to write a custom class to hold that information:

public class Person {
  private final String name;
  private final double score;

  public Person(final String name, final double score) {
    this.name=name;
    this.score=score;
  }

  public String getName() {
    return name;
  }

  public double getScore() {
    return score;
  }
}

Then, when you want to sort them, you simply implement a Comparator<Person> that specifies how you want them sorted:

public PersonScoreComparator implements Comparator<Person> {
  public int compare(Person p1, Person p2) {
    return Double.compare(p1.getScore(), p2.getScore());
  }
}

Alternatively, you could have the Person class itself implement Comparable<Person> by adding this method:

public int compareTo(Person other) {
  return Double.compare(getScore(), other.getScore());
}

public static void main(String[] args) {

String Name[][]={{"prakash","kumar"},{"raj","kappor"},{"vinod","bhart"}};

String str[]=new String[2];


for(int j=0; j<Name.length;j++)
 {
     for (int i=0 ; i<2; i++)
     {
         str[i]=Name[j][i];
     }
 for(int i=0;i<str.length;i++)
 {
     for(int k=i+1;k<str.length;k++)
     {
         if(str[i].compareTo(str[k])>0)
         {
             String temp= str[i];
             str[i]=str[k];
             str[k]=temp;
         }

         }
     System.out.print(str[i]+ " ");
  }
 System.out.println();
 }



 }
}
/**
     *
     * @param array - 2D array required to be arranged by certain column
     * @param columnIndex - starts from 0; this will be the main comparator
     * @param hasHeaders - true/false; true - ignore the first row. False -
     * first row it's also compared and arranged
     * @return - the new arranged array
     */
    private String[][] arrangeArray(String[][] array, int columnIndex, boolean hasHeaders) {
        int headersExists = 0;
        if (hasHeaders) {
            headersExists = 1;
        }
        for (int i = headersExists; i < array.length; i++) {
            for (int j = headersExists; j < array.length; j++) {
            if (array[i][columnIndex].compareTo(array[j][columnIndex]) < 0){
                String[] temp = array[i];
                array[i] = array[j];
                array[j] = temp;
            }
        }
    }
    return array;
}

- 使用 Arrays.toList() 从该数组中创建列表 - 使用 java.lang.comparator 设计比较器并编写用于对每个偶数元素进行排序的逻辑

There are several sort methods in java.util.Arrays . Two of them take custom Comparator s. Simply provide a comparator comparing the second element of the inner arrays.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM