【问题标题】:Ordering Set by Instant即时订购集
【发布时间】:2018-07-13 17:26:43
【问题描述】:

我有一个 Java Set,我将信息提供给:

Set<myData> dataLocations = getData(location);

我想对这个 Set 进行排序 我尝试了 sortedSet 但无法让它工作,所以我尝试了这个

dataLocations = dataLocations.stream().sorted(Comparator.comparing(myData -> myData.expDtTm)).collect(Collectors.toSet());

唯一的问题是在 Java 文档中它不保证保留任何订单。所以我尝试了这个:

TreeSet<myData> sortedDataLocations = dataLocations.stream().sorted(Comparator.comparing(myData -> myData.expDtTm)).collect(Collectors.toCollection(TreeSet<myData>));

不用说它不起作用,所以任何有其他想法的人都会非常感激。

【问题讨论】:

  • 请使用有序的数据结构,例如List。所以排序后使用Collectors.toList()
  • myData 的基本定义,我猜是自定义类的实例?定义无法使其工作任何异常、错误消息或特定的元素顺序?
  • TreeSeta constructor 需要一个 Comparator
  • @Slaw 但是Collectors.toSet() 没有设置工厂。所以你不会知道你得到了哪个确切的Set 实现
  • TreeSetComparator 如下面的答案所示是处理此问题的好方法。要添加到您的工具箱中的其他内容:LinkedHashSetSet 实现,其迭代顺序与元素插入顺序相同。

标签: java collections java-stream java.time.instant


【解决方案1】:

您可以使用TreeSet 并提供一个比较器

TreeSet<myData> sorted = new TreeSet<>(Comparator.comparing(MyData::expDtTm));
sorted.addAll(dataLocations);

或如Collector 类Javadocs 中所述,为TreeSet 创建您自己的收集器:

Collector<Widget, ?, TreeSet<Widget>> intoSet =
     Collector.of(
         TreeSet::new, 
         TreeSet::add,
         (left, right) -> { left.addAll(right); return left; }
     );

【讨论】:

  • 您可以简单地使用Collectors.toCollection(() -&gt; new TreeSet&lt;&gt;(yourComparator));,而不是直接创建自定义Collector。它为您处理积累和组合。
【解决方案2】:

您的第三次尝试很接近,尽管书面没有编译。方法Collectors.toCollection 采用Supplier,它返回所需的Collection,而不是Collection 本身。

如果MyData 被定义为:

public class MyData {
  private Instant instant;
  public Instant getInstant() { return instant; }
  public void setInstant(Instant instant) { this.instant = instant; }
}

然后为了通过Streams 将它们收集到SortedSet 中,您可以这样做:

Comparator<MyData> comparator = Comparator.comparing(MyData::getInstant);
TreeSet<MyData> set = getMyData().stream()
            .collect(Collectors.toCollection(() -> new TreeSet<>(comparator));

请注意,我在这里不使用Stream.sorted。如果您使用Stream.sorted 实际上是有害的,因为它增加了无助于最终结果的工作。 Stream 会对它的元素进行排序,然后开始将它们添加到TreeSetTreeSet 也会对元素进行排序。

也就是说,在某些情况下使用Stream.sorted 会有所帮助:当Stream.collect 返回保证插入顺序的Collection 时。 LinkedHashSet 以及 List 的任何实现都保证了插入顺序。所以你可以这样做:

LinkedHashSet<MyData> set = getMyData().stream()
            .sorted(comparator)
            .collect(Collectors.toCollection(LinkedHashSet::new));
// Or use a List
List<MyData> list = getMyData().stream()
            .distinct() // If you want only unique elements in the end List
            .sorted(comparator)
            .collect(Collectors.toList());

注意:结尾Collection 保证插入顺序是不够的。正在使用的Collector 不能将unordered 用作characteristicCollectors.toCollectionCollectors.toList 返回的 Collectors 就是这种情况。使用Collectors.toSet不是

【讨论】:

  • 一个很好的详细答案! +1
【解决方案3】:

你试试这个:

public class Example {
  public static void main(String[] args) {
    Comparator<String> stringComparator =
      Comparator.comparing((String x) -> x);

    Supplier<TreeSet<String>> supplier =
      () -> new TreeSet<>(stringComparator);

    Set<String> set = new HashSet<>(Arrays.asList("1", "3", "7", "2", "9", "4"));
    TreeSet<String> treeSet = set.stream()
      .collect(Collectors.toCollection(supplier));
    System.out.println(treeSet);
  }
}

将 String 类替换为你的。

输出

[1, 2, 3, 4, 7, 9]

【讨论】:

    【解决方案4】:

    我最终做的是:

    TreeSet<myData> sorted = new TreeSet<>(Comparator.comparing(myData -> myData.ExpDtTm);
    

    现在这不是最佳答案,我仍在寻找另一个答案,因为如果您有 2 个相同的 ExpDtTm,比较器将删除第二个 Instant 含义:

    | Lot Number | ExpDtTm             |
    | LOT-4      | 2018-07-16 12:41:56 |
    | LOT-7      | 2018-07-16 12:41:56 |
    

    这将导致 LOT-7 被删除并且不会返回给用户。

    NOTE: This is also the time that happens when formatting an Instant to just have a date which I did 
    for testing purposes
    

    【讨论】:

      【解决方案5】:
          Comparator<MyData> instantComparator = Comparator
                  .comparing(MyData::getExpDtTm)
                  .thenComparing(MyData::getLotNo);
          SortedSet<MyData> sorted = new TreeSet<>(instantComparator);
          sorted.addAll(dataLocations);
      

      我尝试了以下设置:

      LOT-9 2018-07-15T10:39:53Z
      LOT-1 2018-07-17T14:46:57Z
      LOT-4 2018-07-16T12:41:56Z
      LOT-7 2018-07-16T12:41:56Z
      

      排序后变成:

      LOT-9 2018-07-15T10:39:53Z
      LOT-4 2018-07-16T12:41:56Z
      LOT-7 2018-07-16T12:41:56Z
      LOT-1 2018-07-17T14:46:57Z
      

      一个集合是一个数学集合,它可能只包含每个元素一次。 SortedSetTreeSet 使用它的比较器(或者如果没有提供比较器,则元素的自然排序)来决定两个元素是否相等,因此不能都在集合中。因此,为了按Instant 对元素进行排序并仍然保持具有相同Instant 的元素,我们需要以其他方式区分它们。所以在我的比较器中,我添加了按批号排序。在Instant 之后。如果很多没有。也不是唯一的,您将需要添加更多要排序的属性列表。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-15
        • 2013-01-11
        相关资源
        最近更新 更多