【问题标题】:Sorting through an array list of objects对对象数组列表进行排序
【发布时间】:2018-02-13 20:44:53
【问题描述】:

我正在尝试从包含 4 列的 CSV 文件中读取数据到数组列表中。我们将列称为 a,b,c,d(它们每个都包含整数)。然后我想根据a,b,c,d的行的内容对数组列表进行排序。

因此,例如,如果您比较第 1 行和第 2 行,如果 1d 的值则返回某个值。如果 1d=2d 则将 1c 与 2c 进行比较,依此类推。我无法找到一种方法来创建允许我区分和比较每一行/列的数组列表。

public class Speed {
    public static void main(String[] args) throws IOException {
        // TODO code application logic here
        readCSV();
    }

    public static void readCSV() throws FileNotFoundException, IOException {
        BufferedReader br = new BufferedReader(new FileReader("amis.csv"));
        String line = "";
        ArrayList<String> amis = new ArrayList<String>();
        while ((line = br.readLine()) != null) {
            line = line.replaceAll("\"", "");

            amis.add(line);
        }

        amis.remove(0);

        for (String alphabet: amis) {
            Object[] parts = alphabet.split(",");
            Object studentID = (parts[0]);
            Object a = parts[1];
            Object b = parts[2];
            Object c = (parts[3]);
            Object d = parts[4];
            ArrayList<Object> Compare = new ArrayList();

            Compare.add(a);
            Compare.sort(new customComparator());
        }

我的自定义比较器类

public class customComparator implements Comparator<Object> {
    public int compare(Object o1, Object o2) {
        int a = (Integer) o1;
        int b = (Integer) o2;

        if (a < b) {
            return 1;
        }
        else if(a > b)
            return -1;
        else
            return 0;
    }
}

【问题讨论】:

  • 为什么要用Object[] parts = alphabet.split(","); 将字符串更改为对象?看起来您稍后将 Objects (really Strings) 转换为整数,这肯定至少会产生运行时错误?

标签: java csv sorting object arraylist


【解决方案1】:

我们来看看你目前的排序方式

for(String alphabet: amis)
{
    Object[] parts = alphabet.split(",");
    Object studentID = (parts[0]);
    Object a = parts[1];
    Object b = parts[2];
    Object c = (parts[3]);
    Object d = parts[4];
    ArrayList<Object> Compare = new ArrayList();

    Compare.add(a);
    Compare.sort(new customComparator());
}

最明显的问题是你正在创建一个 ArrayList,比较,添加/排序,然后丢弃它

如果您要创建第二个排序列表:

List<String> sorted = new ArrayList<String>(amis);
sorted.sort(new CustomComparator());

如果您只是想对原始列表进行排序:

amis.sort(new CustomComparator());

通过制作比较器,您已经非常接近您想要做的事情,但它需要调整

您当前的实现在检查第一个值后停止,它返回 0 而不是继续

public class CustomComparator implements Comparator<String>
{
    public int compare(String A, String B)
    {
        String[] as = A.split(",");
        String[] bs = B.split(",");

        int a = Integer.parseInt(a[4]); //column d, as an int
        int b = Integer.parseInt(b[4]);
        if(a < b)
            return 1;
        else
            if(a > b)
                return -1;
            else
            {
                a = Integer.parseInt(a[3]); //column c, as an int
                b = Integer.parseInt(b[3]);
                if(a < b)
                    return -1;
                else
                    if(a > b)
                        return 1;
                    else
                    {
                        a = Integer.parseInt(a[2]); //column b, as an int
                        b = Integer.parseInt(b[2]);
                        if(a < b)
                            return -1;
                        else
                            if(a > b)
                                return 1;
                            else
                            {
                                a = Integer.parseInt(a[1]); //column a, as an int
                                b = Integer.parseInt(b[1]);
                                if(a < b)
                                    return -1;
                                else
                                    if(a > b)
                                        return 1;
                                    else
                                        return 0; //all columns are the same
                            }
                    }
            }
    }
}

注意到有很多类似的代码,我们可以将其改为循环

public int compare(String A, String B)
{
    String[] as = A.split(",");
    String[] bs = B.split(",");

    for(int i = 4; i >= 1; i--) //columns d-a
    {
        int a = Integer.parseInt(a[i]);
        int b = Integer.parseInt(b[i]);
        if(a < b)
            return -1;
        if(a > b)
            return 1;
    }
    return 0;
}

【讨论】:

  • 感谢您的回答 - 效果很好。只是一个简单的问题,我不明白字符串拆分方法如何允许将 csv 文件分成列而不是行。
  • @Abby 逐行读取时,行存储在 ArrayList 中,对 ArrayList 中的每一行使用 split 将给出列
【解决方案2】:

您应该为每个字符串创建 POJO 并为其创建比较器。在比较器中,您应该首先比较更“重要”的列,如果之前的列相等,则转到不太重要的列。

public class Pojo {
private int a;
private int b;
private int c;
private int d;

public int getA() {
    return a;
}

public void setA(int a) {
    this.a = a;
}

public int getB() {
    return b;
}

public void setB(int b) {
    this.b = b;
}

public int getC() {
    return c;
}

public void setC(int c) {
    this.c = c;
}

public int getD() {
    return d;
}

public void setD(int d) {
    this.d = d;
}

public static class PojoComparator implements Comparator<Pojo> {

    @Override
    public int compare(Pojo pojo1, Pojo pojo2) {
        return pojo1==null ? (pojo2==null ? 0:1) :(pojo2==null?-1:
                (pojo1.d!=pojo2.d? pojo1.d-pojo2.d : 
                (pojo1.c!=pojo2.c ? pojo1.c-pojo2.c: 
                (pojo1.b!=pojo2.b? pojo1.b-pojo2.b:
                        pojo1.a-pojo2.a))) );
    }
  }
  }

【讨论】:

  • 只使用公共变量可能更简洁,而不是使用公共私有变量