考虑排序值相同的情况下取前几名数据工具

考虑排序值相同的情况下取前几名数据工具

  1. 数据:[1,2,3,3,3,4,5]
    a. 取前 3 名返回:[1,2,3,3,3]
    b. 取前 4 名返回:[1,2,3,3,3]
  2. 数据:[1,2,3,4,5]
    a. 取前 3 名返回:[1,2,3]
    b. 取前 4 名返回:[1,2,3,4]
  3. 数据:[5,4,3,2,1]
    a. 取前 3 名返回:[1,2,3]
    b. 取前 4 名返回:[1,2,3,4]

工具类主体

import cn.hutool.core.collection.CollUtil;
import lombok.Getter;
import org.apache.commons.collections4.CollectionUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 考虑排序值相同的情况下取前几名的数据
 * <pre>
 *     1. 数据:[1,2,3,3,3,4,5]
 *        a. 取前 3 名返回:[1,2,3,3,3]
 *        b. 取前 4 名返回:[1,2,3,3,3]
 *     2. 数据:[1,2,3,4,5]
 *        a. 取前 3 名返回:[1,2,3]
 *        b. 取前 4 名返回:[1,2,3,4]
 *     3. 数据:[5,4,3,2,1]
 *        a. 取前 3 名返回:[1,2,3]
 *        b. 取前 4 名返回:[1,2,3,4]
 * </pre>
 *
 * @author Neo
 * @since 2022/9/16 21:01
 */
@Getter
public class RankContext<T, V> {

    /**
     * 原始数据
     */
    private Collection<T> originalCollect;

    /**
     * 值映射
     */
    private Function<T, V> valueMapper;

    /**
     * 排序方式
     */
    private Comparator<? super T> comparator;

    /**
     * 排序后的原始数据
     */
    private List<T> sortedCollect;

    /**
     * 排序后的值
     */
    private List<V> sortedValueList;

    /**
     * 构建
     *
     * @author Neo
     * @since 2022/10/10 20:37
     */
    public static <T, V> RankContext<T, V> build(Collection<T> originalCollect,
                                                 Function<T, V> valueMapper,
                                                 Comparator<? super T> comparator) {
        if (CollectionUtils.isEmpty(originalCollect)) {
            return new RankContext<>();
        }

        // 对原始数据根据 Value 排序
        List<T> sortedCollect = originalCollect.stream().sorted(comparator).collect(Collectors.toList());

        // 映射 Value
        List<V> sortedValueList = sortedCollect.stream().map(valueMapper).collect(Collectors.toList());

        return new RankContext<>(originalCollect, valueMapper, comparator, sortedCollect, sortedValueList);
    }

    /**
     * 取前几名的数据
     *
     * @author Neo
     * @since 2022/9/16 09:12
     */
    public List<T> top(int n) {
        if (n < 1) {
            return Collections.EMPTY_LIST;
        }
        if (this.sortedCollect.size() <= n) {
            return new ArrayList<>(this.sortedCollect);
        }

        V value = this.sortedValueList.get(n);

        int lastIndex = this.sortedValueList.lastIndexOf(value);

        return CollUtil.sub(sortedCollect, 0, lastIndex + 1);
    }

    /**
     * 排名
     * sortedValueList = [1,2,2,3,3,3]
     * 输入    输出
     * 1      1
     * 2      2
     * 3      4
     *
     * @author Neo
     * @since 2022/10/10 20:26
     */
    public int rank(V value) {
        return this.sortedValueList.indexOf(value) + 1;
    }

    /**
     * 倒数排名
     * sortedValueList = [1,2,2,3,3,3]
     * 输入    输出
     * 1      6
     * 2      4
     * 3      1
     *
     * @author Neo
     * @since 2022/10/10 20:26
     */
    public int reverseRank(V value) {
        return this.sortedValueList.size() - this.sortedValueList.lastIndexOf(value);
    }


    private RankContext() {
    }


    private RankContext(Collection<T> originalCollect,
                        Function<T, V> valueMapper,
                        Comparator<? super T> comparator,
                        List<T> sortedCollect,
                        List<V> sortedValueList) {
        this.originalCollect = originalCollect;
        this.valueMapper = valueMapper;
        this.comparator = comparator;
        this.sortedCollect = sortedCollect;
        this.sortedValueList = sortedValueList;
    }
}

测试类

import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Comparator;
import java.util.List;

public class RankContextTest {
    public static void main(String[] args) {
        List<Student> collect = Lists.newArrayList(
                new Student(1, 7),
                new Student(2, 6),
                new Student(3, 5),
                new Student(3, 4),
                new Student(3, 3),
                new Student(3, 2),
                new Student(4, 1)
        );


        System.out.println("按成绩排序取倒数 3 名");
        List<Student> result = RankContext.build(collect, Student::getScore, Comparator.comparing(Student::getScore)).top(3);
        for (Student student : result) {
            System.out.println(student);
        }

        System.out.println("按成绩排序取前 3 名");
        result = RankContext.build(collect, Student::getScore, Comparator.comparing(Student::getScore).reversed()).top(3);
        for (Student student : result) {
            System.out.println(student);
        }


        RankContext<Student, Integer> rankContext = RankContext.build(
                collect,
                Student::getRank,
                Comparator.comparing(Student::getRank, Comparator.reverseOrder())
        );
        System.out.println("按排名排序取倒数 2 名");
        result = rankContext.top(2);
        for (Student student : result) {
            System.out.println(student);
        }

        System.out.println("按排名排序取倒数 3 名");
        result = rankContext.top(3);
        for (Student student : result) {
            System.out.println(student);
        }
    }


    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Student {
        private Integer score;
        private Integer rank;
    }
}

测试结果

按成绩排序取倒数 3 名
Student{score=1, rank=7}
Student{score=2, rank=6}
Student{score=3, rank=5}
Student{score=3, rank=4}
Student{score=3, rank=3}
Student{score=3, rank=2}
按成绩排序取前 3 名
Student{score=4, rank=1}
Student{score=3, rank=5}
Student{score=3, rank=4}
Student{score=3, rank=3}
Student{score=3, rank=2}
Student{score=2, rank=6}
按排名排序取倒数 2 名
Student{score=1, rank=7}
Student{score=2, rank=6}
按排名排序取倒数 3 名
Student{score=1, rank=7}
Student{score=2, rank=6}
Student{score=3, rank=5}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值