即时订货

Ordering Set by Instant

我有一个 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>));

不用说它没有用,所以任何有任何其他想法的人都将不胜感激。

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

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

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

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

你试试这个:

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);
  }
}

将字符串 class 替换为您的。

输出

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

您的第三次尝试已接近尾声,但无法编译。方法 Collectors.toCollection takes a Supplier that returns the desired Collection,而不是 Collection 本身。

如果 MyData 被定义为:

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

然后为了将它们收集到一个 SortedSet via Stream 中,您可以这样做:

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

请注意,我不使用 Stream.sorted here. It is actually detrimental if you were to use Stream.sorted because it adds work that doesn't help the end result. The Stream would sort its elements and then later start adding them to the TreeSet 也会对元素进行排序

也就是说,在某些情况下使用 Stream.sorted 是有益的:当 Stream.collect returns a Collection that guarantees insertion order. A LinkedHashSet, as well as any implementation of 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 being used must not have unordered as a characteristic. This is the case with the Collectors returned by Collectors.toCollection and Collectors.toList. It is not the case when using Collectors.toSet.

我最后做的是:

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
    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

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