【问题标题】:Best practice for ordering a list with one of four rules使用四个规则之一对列表进行排序的最佳实践
【发布时间】:2012-11-21 07:36:50
【问题描述】:

我有一系列需要按规则排序的对象。但是我需要能够切换规则,但是我有一组有限的排序规则。哪种数据结构是最好的选择?

作为一个例子,我有这个类:

class Test {
    public final int amount;
    public final int cost;
    public final String name;
    public final int whatever;
    // ...

    // TODO: add a constructor to set the fields :-)
}

我如何存储这些字段以按金额、成本、名称或其他方式对其进行排序。但只是其中一条规则。

我可以想象使用ArrayListHashSet,我使用自定义Comparator 调用排序函数。但我无法想象这就是效率。我认为这在移动设备上很重要。有什么更好的方法来实现这一目标?

【问题讨论】:

    标签: java android performance list


    【解决方案1】:

    您不能使用Set 进行排序,因为它没有任何顺序。拥有List 和自定义Comparator<T> 的每个概念是多么合理。

    您应该采用该解决方案,此时不要关心性能。如果您对获得的结果不满意,请尝试提出更好的解决方案。

    最好的解决方案是以正确的顺序从存储中读取数据。我不知道你的应用程序商店是如何结构的。因此,我无法帮助您。但是实施类似的解决方案,你会发现还不错。

    在移动设备上重要的是内存使用情况。如果您的应用程序将使用大量排序操作,您可以将比较器创建为枚举,这样它们只会被加载一次,此外还可以简化代码

    private enum  TestComparator implements Comparator<Test> {
     BY_NAME {
    
        @Override
        public int compare(Test o1, Test o2) {
    
           //We validate first against null
    
           return o1n.name.compareTo(o2.name);
    
        }               
      }
     BY_WHATEVER{
    
        @Override
        public int compare(Test o1, Test o2) {
    
           //We validate first against null
          return (o1.whatever<o2.whatever ? -1 : (o1.whatever==o2.whatever ? 0 : 1));
        }               
      }
    
    }
    

    【讨论】:

      【解决方案2】:

      这样做:

      class Test {
      public final int amount;
      public final int cost;
      public final String name;
      public final int whatever;
      // ...
      
      // TODO: add a constructor to set the fields :-)
      
          class TestAmountComparator implements Comparator<Test> {
              @Override
              public int compare(Test t1, Test t2) {
                  return Integer.valueOf(t1.amount).compareTo(Integer.valueOf(t2.amount))          
              }
          }
      
          class TestCostComparator implements Comparator<Test> {
              @Override
              public int compare(Test t1, Test t2) {
                  return Integer.valueOf(t1.cost).compareTo(Integer.valueOf(t2.cost))          
              }
          }
      

      }

      将您的测试对象存储在ArrayList(或任何其他集合)中,然后以这种方式对它们进行排序:

      List<Test> list = new ArrayList<Test>(myTest); //your Test list
      //sorting
      Collections.sort(list, new TestAmountComparator()); //sort by amount
      Collections.sort(list, new TestCostComparator()); //sort by cost
      

      【讨论】:

      • 比较“成本”为 Integer.compare(t1.cost, t2.cost); “金额”也一样
      【解决方案3】:

      我宁愿实现 Comparable interface 并在类中实现 compareTo 方法。它提供了跨不同数据结构排序的一致性行为。 在这种情况下,比较器接口将仅在需要特殊排序时使用。

      class Test implements Comparable {
          public final int amount;
          public final int cost;
          public final String name;
          public final int whatever;
          // ...
          //add equals ,hashcode, and compareTo method in the class...
          // TODO: add a constructor to set the fields :-)
      }
      

      如果实例是唯一的并且实现了可比较,您可以使用 TreeSet。否则,您必须使用列表并使用 Collection.sort 函数对其进行排序。

      您可以根据访问使用情况来决定 DS。如果要按顺序访问元素,请使用 LinkedList else user ArrayList

      【讨论】:

      • TreeSet 的提示是好的。但不适用于这个问题,因为 OP 要求在同一模型上使用不同的比较器。
      • 实际上,如果当 t1.amount == t2.amount 时 compareTo 返回 1,则按金额排序的 TreeSet 可以有相同数量的实例
      • 有java.util.PriorityQueue,它也是排序的,但可以容纳重复
      • @EvgeniyDorofeev Set 只能有唯一的对象。如果 2 个对象相等,则不会将第二个对象附加到集合中。 compareTo 的实现必须依赖于实现者...
      • 如果要添加重复的实例,那么 set 将丢弃第二个条目。
      【解决方案4】:

      我的版本:

      class Test3 implements Comparable<Test3> {
          public int amount;
          //...
      
          Comparator<Test3> comparator;
      
          public void setComparator(Comparator<Test3> comparator) {
              this.comparator = comparator;
          }
      
          @Override
          public int compareTo(Test3 o) {
              return comparator.compare(this, o);
          }
      }
      

      【讨论】:

        【解决方案5】:

        这就是我们可以在不丢失重复项的情况下使用 TreeSet 的方法:

        import java.util.Comparator;
        import java.util.TreeSet;
        
            public class Test {
                int amount;
        
                Test(int amount) {
                    this.amount = amount;
                }
        
                public static void main(String args[]) throws Exception {
                    Comparator<Test> c = new Comparator<Test>() {
                        @Override
                        public int compare(Test o1, Test o2) {
                            if (o1.amount >= o2.amount) {
                                return 1;
                            }
                            return -1;
                        }
                    };
                    TreeSet<Test> s = new TreeSet<Test>(c);
                    s.add(new Test(2));
                    s.add(new Test(1));
                    s.add(new Test(1));
                    for (Test t : s) {
                        System.out.println(t.amount);
                    }
        
                }
            }
        

        打印出来:

        1
        1
        2
        

        【讨论】:

        • 如果金额相等,您的比较器不会返回有效结果。
        • 但这就是为什么相等的对象保留在 TreeSet 中,整个事情正常工作。
        猜你喜欢
        • 2018-04-19
        • 1970-01-01
        • 2013-07-03
        • 1970-01-01
        • 1970-01-01
        • 2011-10-22
        • 2012-11-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多