【问题标题】:sort by nullable field saying the item's position按表示项目位置的可空字段排序
【发布时间】:2019-05-06 05:01:25
【问题描述】:

我需要以自定义方式对我的对象数组进行排序。 假设我的对象中有两个字段——priority(可空)和createdAt(不可空)。 优先级字段说明项目应该在哪个位置。但是,它可以为空。在这种情况下,我们应该考虑 createdAt 字段(按降序排列)进行排序。

让我用例子来解释一下。 例如我的对象是:

Object0: priority: null, createdAt: 2018-12-01
Object1: priority: 1,    createdAt: 2018-12-02
Object2: priority: 5,    createdAt: 2018-12-03
Object3: priority: null, createdAt: 2018-12-04
Object4: priority: null, createdAt: 2018-12-05
Object5: priority: 2,    createdAt: 2018-12-06
Object6: priority: null, createdAt: 2018-12-07

最终的顺序应该是:

  1. Object1(按其优先级)
  2. Object5(按其优先级)
  3. Object6(通过 createdAt desc 填充左侧位置)
  4. Object4(通过 createdAt desc 填充左侧位置)
  5. Object2(按其优先级)
  6. Object3(通过 createdAt desc 填充左侧位置)
  7. Object0(通过 createdAt desc 填充左侧位置)

我怎样才能实现我的目标?是否有现成可用的比较器?

编辑: 我认为我们可以使用该类:

public class MyObject {
   Integer priority;
   LocalDateTime createdAt;
}

【问题讨论】:

  • 可以给相关的课吗?
  • 老实说,我没有这门课。我的情况更复杂,在这里我将其减少到最低限度。我将编辑我的帖子,但提供最低级别。
  • 为什么object6和object4在object5和object2之间?您可以使用自己的比较器 lambda 轻松排序,但我不清楚您的算法。
  • Object5 的优先级为 2,所以它会到达位置 2。Object2 的优先级是 5,所以它会到达位置 5。当我们将所有对象都放在它们的位置时,我们使用排序的对象填充数组中的左侧空格创建于。我希望现在会更清楚。
  • 你不能这样排序,因为你说你需要优先级作为索引,这不是它的工作方式,你只能比较它们之间的元素,之前/之后/等于

标签: java spring java-stream comparator comparable


【解决方案1】:

不,不要为此使用比较器,或者更准确地说,不要为整个工作使用比较器。比较器的工作是比较两个对象并判断这两个对象之间的顺序。它不适用于检测优先级序列中的间隙。

相反,假设优先级是完整且唯一的,我建议您对具有已定义优先级的对象使用数组和一种基数排序。优先级 1 进入数组索引 1,优先级 2 索引 2 等。具有null 优先级的对象在创建日期降序时使用比较器进行排序,然后填充到仍然为null 的数组索引中(索引 0 除外,我猜)。

“假设优先级是完整且唯一的”我的意思是您不会冒两个优先级为 3 的对象或优先级为 2.44 的对象的风险。

我可能会使用流和Collectors.partitioningBy 将具有优先级的对象与不具有优先级的对象分开,但当然还有其他方法。

我会亲自编写代码。我从未听说过任何现成的解决方案。搜索永远不会有害,但我会惊讶地找到一个。另一方面,不需要那么多代码行。

顺便说一句,您的日期使用LocalDate,因为他们没有一天中的时间(不是LocalDateTime)。

【讨论】:

  • 好的。所以我知道没有比较器。这是有道理的:)你知道任何现成的解决方案吗?
【解决方案2】:

给定所有对象的列表:一个数组可以很好地设置优先级的位置:

List<MyObject> list = new ArrayList<>(Arrays.asList(...));
MyObject[] res = new MyObject[list.size()];
  1. 遍历你必须放置优先级的对象

    for (Iterator<MyObject> ite = list.iterator(); ite.hasNext(); ) {
        MyObject obj = ite.next();
        if (obj.getPriority() != null) {
            res[obj.getPriority() - 1] = obj;
            ite.remove();
        }
    }
    
  2. 按降序排列createdAt

    list.sort(Comparator.comparing(MyObject::getCreatedAt).reversed());
    
  3. 将它们插入数组的空框中

    int indicList = 0;
    for (int i = 0; i < res.length; i++) {
        if (res[i] == null) {
            res[i] = list.get(indicList++);
        }
    }
    

【讨论】:

  • 是的,我就是这个意思。 :-) 您可能需要考虑到最大优先级可能大于对象的数量,我不知道,提问者应该知道。
【解决方案3】:

一种涉及流的可能方式(不太确定效率)可能是:

List<CustomObject> customObjectList = new ArrayList<>(); // your initialisation;

// list of only those objects whose priority is null sorted descending by createdAt
List<CustomObject> nullValues = customObjectList.stream()
        .filter(a -> a.getPriority() == null)
        .sorted(Comparator.comparing(CustomObject::getCreatedAt).reversed())
        .collect(Collectors.toList());

// remaining non null priority objects sorted by priority ascending
List<CustomObject> remainingValues = customObjectList.stream()
        .filter(a -> a.getPriority() != null)
        .sorted(Comparator.comparing(CustomObject::getPriority))
        .collect(Collectors.toList());

// final list of same size as initial
List<CustomObject> finalList = new ArrayList<>(customObjectList.size());

// set the priority based indexes first
remainingValues.forEach(a -> finalList.add(a.getPriority(), a));

// iterate through the final list and fill in the empty slots 
// while popping(`remove(0)`) the element from list sorted descending by createdAt
IntStream.range(0, finalList.size())
        .filter(i -> finalList.get(i) == null)
        .forEach(i -> finalList.add(i, nullValues.remove(0)));

注意:这里的假设很少 - 列表中设置了基于0 的优先级。 - 非空优先级值是finalList中的确切索引

【讨论】:

  • 我认为finalList.set(a.getPriority(), a) 会抛出java.lang.IndexOutOfBoundsException: Index: 1, Size: 0,将set 更改为add 确实会改变问题
  • @azro 没测试这个,更新为使用add
  • f*** 我的大脑总是忘记“不”......大脑太快了,“更改添加不会改变问题”不知道如何解决它
  • @azro 好的,让我用更好的测试代码回到它,如果是这种情况,主要是需要初始化列表。
猜你喜欢
  • 1970-01-01
  • 2013-11-02
  • 2014-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-14
相关资源
最近更新 更多