即时订购集

时间:2018-07-13 17:26:43

标签: java collections java-stream java.time.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>));

不用说它不起作用,因此任何有其他想法的人都会受到赞赏。

5 个答案:

答案 0 :(得分:5)

您可以使用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; }
     );

答案 1 :(得分:3)

您的第三次尝试已接近完成,尽管编写时未编译。方法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; }
}

然后,为了通过SortedSet将它们收集到Stream中,您可以执行以下操作:

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

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

也就是说,在某些情况下,使用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作为characteristicCollectorCollectors.toList返回的Collectors.toCollection就是这种情况。使用Collectors.toSet 的情况不是

答案 2 :(得分:1)

您尝试以下操作:

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]

答案 3 :(得分:0)

我最终要做的是:

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

答案 4 :(得分:0)

    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

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