java集合指定元素排序:最前,按照提供的顺序排序?求算法

    List<String> orderings= Stream.of("温度", "运行时间").collect(Collectors.toList());
        List<String> target= Stream.of("温度1", "运行时间ss","运行时间", "温度").collect(Collectors.toList());

如上数据源:
要排序target。
要求最终效果:

List<String> target= Stream.of("温度", "运行时间", "温度1","运行时间ss").collect(Collectors.toList());

缺陷方法:

    Ordering ordering = Ordering.explicit(orderings);

        List<String> strings = target.stream().sorted(new Comparator<String>() {
            @Override
            public int compare (String o1, String o2) {
                if (target.contains(o1) && target.contains(o2)) {
                    return ordering.compare(o1, o2);
                } else {
                    return 0;
                }
            }
        }).collect(Collectors.toList());

但是这样,只会排序 含有orderings元素的 数据。求合理灵活便捷优雅(是优雅的,是优雅的,是优雅的,别for循环ifelse)的算法

阅读 9.1k
3 个回答

山不转那水在转。

既然,给出的标准排序 不够数,那就跟 要排序的 数据 对比进行合并,筹够数,那么最终符合我的安排的排序方法。只加多一句代码

这种对比字符串的可能意义不大。但这是简化需求的。实际target是对象,Map就有这个必要了

  List<String> orderings= Stream.of("温度", "运行时间").collect(Collectors.toList());
        List<String> target= Stream.of("温度1", "运行时间ss","运行时间", "温度").collect(Collectors.toList());
        // 补充数据
        List<String> newOrdering = Stream.concat(orderings.stream(), target.stream().filter(item -> !orderings.contains(item))).collect(Collectors.toList());


        Ordering ordering = Ordering.explicit(newOrdering);

        List<String> strings = target.stream().sorted(new Comparator<String>() {
            @Override
            public int compare (String o1, String o2) {
                if (newOrdering.contains(o1) && newOrdering.contains(o2)) {
                    return ordering.compare(o1, o2);
                } else {
                    return 0;
                }
            }
        }).collect(Collectors.toList());

        System.out.println(strings);

最终结果:
[温度, 运行时间, 温度1, 运行时间ss]

参照guavaExplicitOrdering类做一些改动就行啦。

        List<String> orderings= Stream.of("温度", "运行时间").collect(Collectors.toList());
        List<String> target= Stream.of( "运行时间ss","运行时间","3","温度1", "温度").collect(Collectors.toList());

        class ExplicitOrdering<T> implements Comparator<T> {

            private Map<T,Integer> indexMap = new HashMap();

            public ExplicitOrdering(List<T> explicit) {
                for (int i = 0; i < explicit.size(); i++) {
                    indexMap.put(explicit.get(i),i);
                }
            }

            @Override
            public int compare(T o1, T o2) {
                return rank(o1) - rank(o2);
            }

            private int rank(T value) {
                Integer rank = indexMap.get(value);
                if (rank == null) {
                    return Integer.MIN_VALUE;
                }
                return rank;
            }
        }

        List<String> strings = target.stream().sorted(new ExplicitOrdering<>(orderings).thenComparing(Comparator.naturalOrder())).collect(Collectors.toList());

        System.out.println(strings);

哈哈哈,不好意思,问了题主那么久...根据我获得需求描述,最后我还是觉得引用新的编程元素来使业务稍微变简单的,我整理到需求应该是:

首先给定一个指定关键字的排序,给出一个字符串列表,对列表进行排序,若字符串列表中包含了关键字,则该这种字符串优先级高,排前面,并且还要根据该字符串所包含的关键字顺序排序,其他没有包含关键字的字符串则靠后,顺序不用关心

所以我引用了新的编程元素,因为给出的orderings是有顺序的,所以只有一个字符串是不能体现这个顺序的,我新增加了一个元素OrderParam

@Getter
@Builder
public class OrderParam{

   private String param;

   // 值越小,优先级越高
   private int order;
}

所以之前的

List<String> orderings= Stream.of("温度", "运行时间").collect(Collectors.toList());

就变为

List<OrderParam> orderings= OrderParams.createOrderings("温度", "运行时间");

这里写了一个工具类OrderParams

public class OrderParams{
    
    /**
     * 根据字符串数组生成OrderParam集合
     * @param params
     * @return
     */
    public static List<OrderParam> createOrderings(String ... params){
        return IntStream.range(0, params.length)
                        .mapToObj(i -> OrderParam.builder().param(params[i]).order(i).build())
                        .collect(Collectors.toList());
    }
}

然后最后的测试类写出来就是这个样子

public class Test {
    
    /**
     * 这里思路很简单,orderings是有顺序,给出的target先按照orderings的顺序设定它的优先级,然后直接根据优先级排序就可以了
     * @param args
     */
    public static void main(String[] args) {
        List<OrderParam> orderings= OrderParams.createOrderings("温度", "运行时间");
        List<String> target= Stream.of("sa", "温度1", "ttttt", "运行时间", "温度", "运行时间ss")
                                   .collect(Collectors.toList());

        List<String> result = target.stream()
                                    .map(t -> toOrderParam(orderings, t))
                                    // 这里已经转化成了OrderParam了,所以直接根据OrderParam的order排序即可
                                    .sorted(Comparator.comparing(OrderParam::getOrder))
                                    .map(OrderParam::getParam)
                                    .collect(Collectors.toList());

        System.out.println(result);
    }

    private static OrderParam toOrderParam(List<OrderParam> orderings, String t) {
        return orderings.stream()
                        .filter(orderParam -> t.contains(orderParam.getParam()))
                        .findFirst()
                        .map(orderParam -> OrderParam.builder().param(t).order(orderParam.getOrder()).build())
                        // 没有包含在orderings里的,就给一个最低优先级即可
                        .orElse(OrderParam.builder().param(t).order(Integer.MAX_VALUE).build());
    }
}

最后执行结果:

clipboard.png

以上就是我的想法。。。问的有点多。。打扰了。。哈哈哈哈

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏