【问题标题】:Properly sort equal items in Collection正确排序集合中的相等项目
【发布时间】:2018-07-26 07:20:24
【问题描述】:

根据Documentation Java SE7

这种排序保证稳定:相同的元素不会因为排序而被重新排序。

 Collections.sort(gpsDtoList, new Comparator<T>() {

                public int compare(T o1, T o2) {

                    return -o1.getEreigniszeit().compareTo(o2.getEreigniszeit());

                }
            });

知道这个事实,我怎么能象征这些项目确实是平等的,即使一个在列表中“更高”(隐含意思更年轻timestamp

测试数据

假设o2.Ereigniszeit = 0000o2.Ereigniszeit = 0000 (这只是一个非常简单抽象的例子)

关键

我稍后会处理这些数据,并使用此逻辑在 Leaflet 地图上突出显示最新的 (green) 和最旧的 (red) 对象

if (i == 0) {
   properties.put("markerStyle", LATEST);
   } else if (i == gpsDtoList.size() - 1) {
        properties.put("markerStyle", OLDEST);
   }

但是它们实际上是equal,我应该如何正确处理它? (我正在处理很多 gps 位置,所以任何 O(N^2) 都是不可接受的。)

返回对象是GpsDTO

public class GpsDTO implements Serializable {
    ....
    public Date getEreigniszeit() {
        return ereigniszeit;
    }

    public void setEreigniszeit(Date ereigniszeit) {
        this.ereigniszeit = ereigniszeit;
    }

【问题讨论】:

  • 您能发布返回getEreigniszeit() 对象的类吗?您想通过哪些属性来订购这些对象?请说出他们的名字。
  • 无论如何您都在提供自定义比较器,为什么不检查 compare() 中的附加字段以防 getEreigniszeit() 返回相等的值?
  • @Yoda by ereigniszeit
  • @user158037 这对我有什么帮助?最后一个项目在第一个之后,即使它是相等的,不是吗?
  • 我会将它们放在Map&lt;GpsDTO, SortedSet&lt;GpsDTO&gt;&gt; 中,这样您就可以将它们分组,然后您可以在渲染时根据它们的日期或列表中的坐标数为它们应用颜色,但我不知道如何你想向用户表明他们的年龄(不知道你的 GUI),也许你会把他们放在一个列表中,因为他们在同一个地方,所以绝对不在地图上。

标签: java algorithm sorting collections comparator


【解决方案1】:

我建议你使用NavigableMap;这些是按它们的键排序的。

// entries will be sorted by your comparator
NavigableMap<Date, List<GpsDTO>> map = new TreeMap<yourComparator>();
// if there is a list already, it will be used; otherwise, a new one will be created
gpsDtoList.forEach(dto -> 
    map.computeIfAbsent(dto.getEreigniszeit(), new ArrayList<>())
                            .add(dto));

// iterate the relevant lists to set the respective markers
map.firstEntry().forEach(dto -> dto.setOldest());
if (map.size() > 1) {
    map.lastEntry().forEach(dto -> dto.setNeweset());
}

没有 lambda 也一样:

NavigableMap<Date, List<GpsDTO>> map = new TreeMap<yourComparator>();
for (GpsDTO dto : gpsDtoList) {
    List<GpsDTO> list = map.computeIfAbsent(dto.getEreigniszeit());
    list.add(dto);
}

for (GpsDTO firstDto : map.firstEntry()) {
    setOldestProperty(firstDto);
}
if (map.size() > 1) {
    for (GpsDTO lastDto : map.lastEntry()) {
        setNewestProperty(lastDto);
    }
}

【讨论】:

  • 我认为我的解决方案与您的解决方案有些相似,但是我没有经常使用 NaviableMaps,这就是为什么我有点怀疑并且我发现很难阅读流 :O 但是感谢您努力! PS:您认为您的解决方案性能更高吗?
  • @0x45 应该是 O(n);一次遍历列表将项目收集到地图中,然后遍历两个子列表,最多添加 n 个额外的操作。我可以添加一个非 lambda 版本。
  • 这将是 O(2*n) 因为你必须触摸每个项目两次。 O(n^n) 意味着您必须为列表中的每个项目迭代一次完整列表。此外,我还添加了防止最新日期和最旧日期相同的保护措施。
  • @0x45 我对复杂性理论有点生疏了,但 IIRC 是的。怀疑你能做得更好; O(n) 至少因为您必须确保能够收集每个元素。
【解决方案2】:

解决方案

首先我确定最新和最旧的日期。

Date youngestDate = null;
Date oldestDate = null;

Collections.sort(gpsDtoList, new Comparator<T>() {

            public int compare(T o1, T o2) {

                return -o1.getEreigniszeit().compareTo(o2.getEreigniszeit());

            }
        });

if (gpsDtoList != null && gpsDtoList.size() > 1) {
            youngestDate = gpsDtoList.get(0).getEreigniszeit();
            oldestDate = gpsDtoList.get(gpsDtoList.size() - 1).getEreigniszeit();
        }

以及实际的设置逻辑

if (youngestDate != null && oldestDate != null) {
                if (i == 0 || youngestDate.equals(gpsDtoList.get(i).getEreigniszeit())) {
                    properties.put("markerStyle", LATEST);
                } else if (oldestDate.equals(gpsDtoList.get(i).getEreigniszeit())) {
                    properties.put("markerStyle", OLDEST);
                }

            }

测试用例/说明

#1 o1,o2 是否相等

youngestDateoldestDate 将被设置,但它们是相同的。

现在,如果i=0 或等于youngestDate 它确实是latest 并获得该属性 否则,如果等于 oldestDate,它确实是最旧的。

所以我们成功地将两个GpsDto 对象设置为latest,因为它永远不会运行else if 语句。

#2 没有数据?

我们做了一些空检查,如果没有数据,我们不会设置特殊属性。

#3 在List 中只有一个GpsDto 对象?

我们不需要在这里设置任何特殊属性,对于我的定义它是“无状态的”,我们不知道它是第一个还是最后一个。 (懒我)

如果我没有完全错,我在 O(n)

【讨论】:

  • 只是好像不知道自己想要什么或者说不出来。我认为这次投票的原因是这个答案与您的问题相对应。
  • @Yoda 到底什么不清楚?我想在 cmets 讨论之后更清楚了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-05-17
  • 1970-01-01
  • 1970-01-01
  • 2012-05-17
  • 1970-01-01
  • 2022-01-04
  • 2021-03-04
相关资源
最近更新 更多