【问题标题】:Java, Sort Array of doubles and its indexesJava,双精度数及其索引的排序数组
【发布时间】:2017-02-15 11:23:33
【问题描述】:

我在这个论坛和其他论坛上阅读了很多关于此的内容,但我仍然无法得到具体的答案。无论如何,我决定这样做:

这是一个保存字符串和整数的类:

public class Tuple{

    private String token;
    private int docID;



    public Tuple(String token, int docID) {
        this.token = token;
        this.docID = docID;
    }

    public String getToken() {
        return token;
    }
    public void setToken(String token) {
        this.token = token;
    }
    public int getDocID() {
        return docID;
    }
    public void setDocID(int docID) {
        this.docID = docID;
    }

}

然后,我创建一个数组列表来放置这些元组private ArrayList<Tuple> temps = new ArrayList<>();

然后我像这样填充数组列表:

for ( int i = 0; i < numberOfDocs; i++ )
{
    Tuple cat = new Tuple(Double.toString(vect[i]),i);
    temps.add(cat);
}

最终,我将数组排序如下:

public void sortTmp() 
{
    Collections.sort(temps, new Comparator<Tuple>() 
    {
        @Override
        public int compare(Tuple tr2, Tuple tr1)
        {
            return tr2.getToken().compareTo(tr1.getToken());
        }
    });
}

java 和 doubles 存在一些问题,我不能直接使用我的 double 矩阵,所以我必须这样做 Double.toString() 。结果已排序,但并不完全正确,因为从 double 计算的字符串在 double 数字排序方面不是很准确。

有什么想法吗?

【问题讨论】:

  • 按词法排序可能不是您想要的。为什么不能使用双打?或者更好:是什么让你认为你做不到? “java 和 doubles 存在一些问题” - 主要是开发人员遇到了 doubles 而不是 java 的问题。
  • @Fildor 当我将所有内容从string 类型更改为double 类型时,此特定行return tr2.getToken().compareTo(tr1.getToken()); 是错误的。根据我的 IDE:double cannot be dereferenced
  • 是的,然后更改 that 行,使其适用于双倍。如果需要使用 compareTo,可以使用 Double 包装器。
  • 你应该阅读this 解释在原语上调用方法会产生这个问题。使用包装器应该可以解决它
  • 例如做return Double.compare( tr2.getToken(), tr1.getToken() );(当改变getToken()返回double时)

标签: java arrays sorting arraylist


【解决方案1】:

如果您按字典顺序比较doubles,通过他们的String 表示,您可能确实会发现一些意想不到的结果。

你可以:

  • 重构Tuple,使token 成为double(或包装Double,如果您想在实例上调用compareTo
  • 否则,在您的Comparator 中,您可以在您的Strings 上调用Double.parseDouble(这应该是相对安全的,因为Strings 首先来自doubles),然后调用@返回的 Double 包装器上的 987654333@。

最后一个选项听起来很丑,因为在DoubleString 之间有一堆看似不必要的来回转换,反之亦然。

这也意味着性能下降,因为在对集合进行排序时会多次调用compareTo

【讨论】:

  • 感谢您的意见。包装器Double 是什么意思?我试图改变我的Tuple 班级;其中string,我输入double,但在return tr2.getToken().compareTo(tr1.getToken()); 行中我收到double cannot be dereferenced 错误。
  • @Javac Double != double 后者是原始的。您不能像尝试那样调用它的函数。 Double 是该原始类型的包装器,以完全允许这样做(以及其他目的)。从double 到对应的Double 被称为“装箱”。
  • @Javac 如果你想使用原语,你可以调用静态Double.compare(double d1, double d2) 而不是调用compareTo。否则,您可以使用 Double 包装器进行重构,正如我所说的,Fildor 也指出了。
  • 我接受这个。那是Double。谢谢
【解决方案2】:

您可以在Tuple 中将令牌存储为双精度并实现Comparable 接口。在getToken 中,您可以以您实际需要的形式返回双精度字符串表示形式。

public class Tuple implements Comparable<Tuple>{

    private double token;
    private int docID;

    public Tuple(double token, int docID) {
        this.token = token;
        this.docID = docID;

    }

    public String getToken() {
        return String.valueOf(token);
    }
    public void setToken(double token) {
        this.token = token;
    }
    public int getDocID() {
        return docID;
    }
    public void setDocID(int docID) {
        this.docID = docID;
    }

    @Override
    public int compareTo(Tuple o) {
        return Double.compare(this.token, o.token);
    }
}

【讨论】:

    【解决方案3】:

    如果你真的需要将双精度转换成字符串,使用起来会更安全

    BigDecimal.valueOf(vect[i])).toString(); 
    

    因为它处理双重不可预测性。

    【讨论】:

    • 好吧,他根本不应该那样做。在双打上按字典顺序排序肯定会带来惊喜。想想将用数学符号表示的值......
    【解决方案4】:

    我和 Vlad Bochenin 有同样的想法:

    您只需实现Comparable 并覆盖compareTo

    public class Tuple implements Comparable<Tuple> {
    
        public Double token;
        public int docID;
    
        public Tuple(final double token, final int docID) {
            this.token = token;
            this.docID = docID;
        }
    
        @Override
        public int compareTo(final Tuple o) {
            return this.token.compareTo(o.token);
        }
    }
    

    还有一个单元测试:

    public class TestTuple {
    
        @Test
        public void testSort() {
            final Random r = new Random(System.currentTimeMillis());
            final int numberOfDocs = 100;
            final ArrayList<Tuple> temp = new ArrayList<Tuple>();
            for (int i = 0; i < numberOfDocs; i++) {
                temp.add(new Tuple(r.nextDouble(), i));
            }
            Collections.sort(temp);
    
            Tuple old = temp.get(0);
            // test if sorted
            for (final Tuple next : temp) {
                Assert.assertTrue(next.token >= old.token);
                old = next;
            }
        }
    }
    

    【讨论】:

      【解决方案5】:

      您可以在 Tuple 中将令牌存储为 double 并实现 Comparable 接口。在 getToken 中,您可以返回实际需要的 double 形式的字符串表示形式。

      private double token;
      private int docID;
      
      public Tuple(double token, int docID) {
          this.token = token;
          this.docID = docID;
      
      }
      
      public String getToken() {
          return String.valueOf(token);
      }
      public void setToken(double token) {
          this.token = token;
      }
      public int getDocID() {
          return docID;
      }
      public void setDocID(int docID) {
          this.docID = docID;
      }
      
      @Override
      public int compareTo(Tuple o) {
          return Double.compare(this.token, o.token);
      }
      

      }

      To see More about CompareTo

      【讨论】:

      • 这是我的答案(以及我糟糕的英语)的全部副本,没有任何参考。开个玩笑吗?
      • 如果您想将链接添加到 Vlad 的答案,请使用评论。不要复制他的答案。
      猜你喜欢
      • 2014-11-06
      • 2019-04-27
      • 1970-01-01
      • 2013-07-13
      • 1970-01-01
      • 2012-12-20
      • 1970-01-01
      • 1970-01-01
      • 2014-07-17
      相关资源
      最近更新 更多