按可空字段排序,说明项目的位置

时间:2018-12-04 17:33:06

标签: java spring java-stream comparator comparable

我需要以自定义方式对对象数组进行排序。 假设我的对象中有两个字段-priority(可为空)和createdAt(不可为空)。 优先级字段表明该项目应位于哪个位置。但是,它可以为null。在这种情况下,我们应考虑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;
}

3 个答案:

答案 0 :(得分:2)

否,请勿为此使用比较器,或者更确切地说,不要针对整个工作使用比较器。比较器的工作是比较两个对象,并确定两个对象之间的顺序。它不适用于检测优先级序列中的缺口。

相反,假设优先级是不可分割的且唯一的,我建议您对定义了优先级的对象使用数组和一种基数排序。优先级1进入数组索引1,优先级2索引2,依此类推。优先级为null的对象在创建日期降序时用比较器进行排序,然后填充到仍为null的数组索引中(除了索引0,我想)。

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

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

我要为此手动编码。我从未听说过任何现成的解决方案。搜索永远不会有害,但是我很惊讶地发现了一个。另一方面,不需要那么多代码行。

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

答案 1 :(得分: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++);
        }
    }
    

答案 2 :(得分:1)

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

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

中的确切索引