【问题标题】:Why does adding "|" to Set in Java flip the elements order?为什么要加“|”在 Java 中设置翻转元素顺序?
【发布时间】:2016-11-28 01:27:25
【问题描述】:

我有两个列表,并试图用每个列表中的元素形成一个字符串,并且在我执行" " 之间时,排序顺序保持不变。但是,一旦我将"|" 放在中间,我想要这样做,Set 中元素的顺序就会被调换。

如何添加 "|" 并仍然保持 Set students 中的排序顺序?

代码如下:

   Set<String> students = new HashSet<>();
   Set<String> fn = new HashSet<>();
   Set<String> nums = new HashSet<>();

   List<String> firstNames = new ArrayList<>(fn);
   Collections.sort(firstNames);

   List<String> favNumbers = new ArrayList<>(nums);
   Collections.sort(favNumbers);

   for(int i=0; i<firstNames.size(); i++) {
       students.add(firstNames.get(i) + "|" + favNumbers.get(i));
   } 

   System.out.println(students);

使用... + " " + ...,顺序为[Joshua 4, Lyon 7],但如果添加"|" 代替" ",则当我想要并且应该是[Joshua|4, Lyon|7] 时,顺序变为[Lyon|7, Joshua|4]

【问题讨论】:

  • 我认为一个完全正确的方法是让一个学生 POJO 和一个自定义比较器一起使用单独的名字和姓氏字段进行排序。
  • @TimBiegeleisen 我怎样才能对我的方法进行修改并让它按照我想要的方式工作?
  • 不太可能,但如果出于某种原因,一个学生的名字中有一根烟斗会怎样?
  • @TimBiegeleisen 更重要的是,学生和他们的分数是独立排序的。如果分数应该与相应的学生匹配,那么您的方法将解决这个问题。愿意将您的评论变成答案吗?
  • @JohnKugelman 我在下面尝试了一个答案。

标签: java list arraylist set


【解决方案1】:

HashSet 不提供任何关于其内容的排序保证,使用基础HashMap 生成的任何排序,而该排序又基于元素的hashCode()

当你改变一个字符串的内容时,你会得到一个不同的哈希码——就这么简单。 HashMap 中的顺序未定义,如果您插入其他触发重新散列的元素,可能会发生变化。

如果您想要一个有保证顺序的集合,您可以使用SortedSet 实现(例如TreeSet),但您需要编写一个适当的类并实现合适的Comparators。或者,您可以使用 LinkedHashSet,它以插入顺序维护元素,但会增加额外开销。

【讨论】:

  • 那么我应该使用什么来代替HashSet&lt;&gt;(); 来代替students
  • @JoKo 你应该有一个Student 类,而不是字符串粘贴或并行数组。
  • 我只是想按元素插入的顺序打印,所以如果 Joshua|4 首先添加,希望它成为打印时的第一个元素,并创建一个 Student 类似乎就像矫枉过正。有更简单的方法吗?
  • @JoKo 如果你有任何结构的数据,那么创建类就是你所做的——就像这样。
【解决方案2】:

您应该使用面向对象的设计,因为 Java 是一种面向对象的语言。与其尝试将学生的各种特征表示为独立集合,不如创建一个包含这些特征的Student POJO。然后,创建自定义比较器以按名称或喜欢的数字排序。

public class Student {
    private String firstName;
    private String lastName;
    private int favNumber;

    // getters and setters

    public static Comparator<Student> NameComparator
                      = new Comparator<Student>() {

        public int compare(Student s1, Student s2) {
            String f1 = s1.getFirstName();
            String f2 = s2.getFirstName();
            String l1 = s1.getLastName();
            String l2 = s2.getLastName();
            if (l1.equalsIgnoreCase(l2) {
                return f1.toUpperCase().compareTo(f2);
            }
            else {
                return l1.toUpperCase().compareTo(l2);
            }
        }
    };

    public static Comparator<Student> FavComparator
                      = new Comparator<Student>() {

        public int compare(Student s1, Student s2) {
            return s1.getFavNumber() < s2.getFavNumber();
        }
    };
}

现在,如果您有学生名单,List&lt;Student&gt; list,您可以通过以下方式排序:

Collections.sort(list, Student.NameComparator);

或者,要按喜欢的数字排序,请使用:

Collections.sort(list, Student.FavComparator);

【讨论】:

    【解决方案3】:

    来自documentation for HashSet

    它不保证集合的迭代顺序;特别是,它不保证订单会随着时间的推移保持不变。

    因此,您不能依赖HashSet 来维护任何类型的订单。

    在我看来,您只需要保留插入顺序,在这种情况下,您最好不要使用Set,而是使用List,例如,

    List<String> students = new ArrayList<>();
    

    【讨论】:

      猜你喜欢
      • 2022-08-13
      • 2015-05-04
      • 1970-01-01
      • 1970-01-01
      • 2012-10-28
      • 2016-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多