【问题标题】:How do I sort a HashSet of objects based on these criteria?如何根据这些条件对对象的 HashSet 进行排序?
【发布时间】:2013-06-20 21:37:10
【问题描述】:

我在这里整理了一个 SSCCE:

House.java:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class House {

    private Status currentStatus;
    private String city;
    private Date date;

    public enum Status { AVAILABLE, 
                         SOLD, 
                         CONTINGENT 
    }

    public House(Status s, String c, String d) throws ParseException {
        currentStatus = s;
        city = c;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        date = sdf.parse(d);
    }
}

SortingTest.java:

import java.text.ParseException;
import java.util.HashSet;
import sortingtest.House.Status;    

public class SortingTest {


    public static void main(String[] args) throws ParseException {
        HashSet<House> houses = new HashSet<House>();
        houses.add(new House(Status.AVAILABLE, "New York City", "2007-11-11"));
        houses.add(new House(Status.SOLD, "Los Angeles", "2005-06-11"));
        houses.add(new House(Status.AVAILABLE, "Chicago", "2012-05-03"));
        houses.add(new House(Status.CONTINGENT, "Portland", "2007-10-11"));

        //Sort HashSet of House objects by criteria listed below      

        //sort by Status.AVAILABLE
            //call sort
            //System.out.println("Sorted by available");
            //iterate set and print out sorted houses

        //sort by Status.SOLD
            //call sort
            //System.out.println("Sorted by sold");
            //iterate set and print out sorted houses

        //sort by Status.CONTINGENT
            //call sort
            //System.out.println("Sorted by contingent");
            //iterate set and print out sorted houses

        //sort by City
            //call sort
            //System.out.println("Sorted alphabetically by City");
            //iterate set and print out sorted houses

        //sort by City
            //call sort
            //System.out.println("Sorted reverse alphabetically by City");
            //iterate set and print out sorted houses

        //sort by Date (newest)
            //call sort
            //System.out.println("Sorted by newest date (fewest days on market)");
            //iterate set and print out sorted houses

        //sort by Date (oldest)
            //call sort
            //System.out.println("Sorted oldest date (most days on market)");
            //iterate set and print out sorted houses
    }
}

所以最终我想创建一个SetSorter 类,我可以在其中调用一个方法,该方法将返回以特定格式排序的 Set。

如果您不想阅读代码中的 cmets,我想根据以下条件进行排序:

  • 状态.可用
  • 状态.已售出
  • 状态.条件
  • 城市(按字母顺序)
  • 城市(字母倒序)
  • 日期(上市最短天数)
  • 日期(上市时间最多)

我对它进行了一些阅读,看起来人们建议将其制成 TreeSet 以进行排序和使用比较器。我见过很多例子,人们要么为比较器创建一个单独的类,要么使指定的类实现可比较。

我还没有看到有人编写了一个额外的类来处理所有的排序。这可能吗?如果是这样,有人可以告诉我从哪里开始吗?这些比较似乎比典型的整数比较稍微复杂一些。

编辑澄清

当按 Status.AVAILABLE 排序时,我希望 Set 让对象按以下方式显示:

  • Status.AVAILABLE(在顶部/第一)
  • Status.CONTINGENT(在 Status.AVAILABLE/秒之后)
  • Status.SOLD(在 Status.CONTINGENT/last 之后)

当按 Status.CONTINGENT 排序时,我希望按如下方式排序:

  • 状态.CONTINGENT
  • 状态.已售出
  • 状态.可用

当按 Status.SOLD 排序时,我希望集合按如下方式排序:

  • 状态.已售出
  • 状态.CONTINGENT
  • 状态.可用

编辑 #2 终极目标

我想要一个类,我可以简单地调用方法来对集合进行排序。

即:

//sort by date
SetSorter.sortByData(treeSet);    //returns TreeSet sorted by date

//sort by city
SetSorter.sortByCity(treeSet);    //returns TreeSet sorted by City

//sort by other criteria 

编辑#3

class SortByCity implements Comparator<House> {
    @Override
    public int compare(House h1, House h2) {
        return h1.getCity().compareTo(h1.getCity());
    } 
}


houses = new TreeSet(new SortByCity());

我认为这是一种简单的方法,但这些都是小类,而且(在我看来)看起来很乱。谁想在 .java 中包含 7 个迷你类?

谁能提供一些替代的例子让我看看?

【问题讨论】:

  • 根据Status.AVAILABLE排序是什么意思?这是一个枚举?
  • @RohitJain 我的意思是,所有的Status.AVAILABLE 在集合的顶部。我将编辑我的帖子以澄清。
  • 使用TreeSet 并提供Comparator&lt;YourClass&gt;
  • @WilliamShatner 是的,因此您需要不同的TreeSets 来以不同的方式对数据进行排序。你的最终目标是什么?顺便说一句,最好有一个List&lt;YourObject&gt; 并使用Collections#sort,每次都提供一个自定义的Comparator&lt;YourObject&gt;
  • 您可以在每个方法上使用自定义比较器,并使用TreeSet(Comparator) 构造函数和TreeSet#addAll 方法。还是不明白做SetSorter.sortXxx的主要目的。

标签: java sorting comparison hashset treeset


【解决方案1】:

这里有一些关于排序的示例。我没有执行日期或反向字母排序(这是一项任务)。请注意关于比较两所房子的价值0的内联评论!

public class HouseSorter {

    enum Status {
        SOLD, AVAILABLE, CONTINGENT;
    }

    /**
     * Immutable house (if a house is sold or not does not change a house, use a
     * Map instead).
     */
    private static class House {
        private final String city;

        House(String city) {
            this.city = city;
        }

        public String getCity() {
            return city;
        }

        @Override
        public String toString() {
            return "House in " + city;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (!House.class.isAssignableFrom(obj.getClass())) {
                return false;
            }
            return this.city.equalsIgnoreCase(((House) obj).city);
        }

        @Override
        public int hashCode() {
            return city.hashCode();
        }
    }

    public static SortedSet<House> sortAlphabetically(Set<House> houses) {
        TreeSet<House> sortedHouses = new TreeSet<House>(
                new Comparator<House>() {
                    @Override
                    public int compare(House o1, House o2) {
                        return o1.getCity().compareTo(o2.getCity());
                    }
                });
        sortedHouses.addAll(houses);
        return sortedHouses;
    }

    public static SortedSet<House> sortByStatus(
            final Map<House, Status> houseStatusMap) {
        TreeSet<House> sortedHouses = new TreeSet<House>(
                new Comparator<House>() {
                    @Override
                    public int compare(House o1, House o2) {
                        int compareByStatus = houseStatusMap.get(o1).compareTo(
                                houseStatusMap.get(o2));
                        if (compareByStatus != 0) {
                            return compareByStatus;
                        }
                        // you need an additional compare, until none of the
                        // houses compare with result 0
                        // otherwise the houses would be equal and therefore
                        // removed from the set
                        return o1.getCity().compareTo(o2.getCity());
                    }
                });
        sortedHouses.addAll(houseStatusMap.keySet());
        return sortedHouses;
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        final Map<House, Status> houseStatusMap = new HashMap<House, Status>();
        House house0 = new House("Beverwijk");
        houseStatusMap.put(house0, Status.SOLD);
        House house1 = new House("Opmeer");
        houseStatusMap.put(house1, Status.SOLD);
        House house2 = new House("Amstelveen");
        houseStatusMap.put(house2, Status.AVAILABLE);
        House house3 = new House("Haarlem");
        houseStatusMap.put(house3, Status.CONTINGENT);

        System.out.println(sortAlphabetically(houseStatusMap.keySet()));
        System.out.println(sortByStatus(houseStatusMap));
    }
}

【讨论】:

  • 谢谢你的例子,我没有时间测试它(我明天会)。 Status 是否需要地图只是因为我想以多种方式比较它?相反,如果我想按枚举的顺序对其进行排序,我还需要地图进行比较吗?再次感谢伟大的示例!我还将尝试搜索数据比较器示例
  • 不,它是面向对象的设计。我不认为“从根本上”说,房子的地位不是房子本身的一部分。一扇门可能是,窗户也是,但外面的小标志不是。
  • 再次感谢您的示例。它真的帮助我理解了这些比较器是如何工作的。不过,我在按状态排序时遇到了一些麻烦(正如您在代码中指出的那样,我需要额外的检查)。如果我只想按序号订购,我的支票会是什么样子?
  • @WilliamShatner 它们按序号排序,因为enum 类的默认compareTo 函数使用序号值。只有enum 不会在第二行打印出来。或者正如 Sun 在 JavaDoc 中所说:“枚举常量只能与相同枚举类型的其他枚举常量进行比较。这种方法实现的自然顺序是声明常量的顺序。”
猜你喜欢
  • 2018-11-01
  • 2016-07-13
  • 1970-01-01
  • 2014-04-18
  • 2014-01-29
  • 2013-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多