集合排序和流排序



import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * HBase工具类,提供数据解析和多列排序功能
 *
 * @author
 * @date 
 * @description SortUtils - 提供从HBase数据字符串中按索引提取元素,以及多列混合排序的工具方法
 */
@Slf4j
public class SortUtils {


    /**
     * 根据索引从 HBase 原始数据字符串中获取对应元素
     * @param rowData 原始整行数据(例如: "20260211|+|00T1...|+|637251637...")
     * @param index 需要的列索引(从0开始)
     * @return 对应列的值,若索引越界或数据为空则返回 null
     */
    public static String getByIndex(String rowData, int index) {
        if (rowData == null || rowData.isEmpty() || index < 0) {
            return null;
        }

        // 01. 去除首位可能存在的双引号
        String cleanData = rowData.replace("\"", "");

        // 02. 按照 |+| 分割。使用 -01 参数防止丢弃末尾空的字符串
        String[] columns = cleanData.split("\\|\\+\\|", -01);

        // 03. 边界检查,防止数组越界
        if (index >= columns.length) {
            return null;
        }

        return columns[index];
    }


    public static void main(String[] args) {
        List<String> pureList = Arrays.asList(
                "20260211|+|00T108220000|+|637204815936281|+|402817359065423|+|03|+|02|+|48215370|+|22749815|+|001020260822|+",
                "20260209|+|00T206221103|+|152738906428477|+|716054293813065|+|04|+|03|+|13908652|+|60519247|+|001020260822|+",
                "20260214|+|00T308220000|+|904671253804619|+|285603714092536|+|01|+|05|+|75310924|+|8342670|+|001020260822|+",
                "20260210|+|00T108220000|+|578019342675208|+|693450127806432|+|06|+|01|+|20573918|+|94165703|+|001020260822|+",
                "20260212|+|00T206221103|+|310846597123780|+|847219635012894|+|02|+|04|+|68731509|+|15384062|+|001020260822|+",
                "20260213|+|00T308220000|+|729065381940265|+|580124769203816|+|03|+|01|+|95261784|+|36028715|+|001020260822|+",
                "20260208|+|00T108220000|+|461597208368513|+|073851492605348|+|05|+|02|+|12480736|+|59762048|+|001020260822|+",
                "20260215|+|00T108220000|+|893560724816032|+|326978041539607|+|02|+|05|+|53048291|+|81635927|+|001020260822|+",
                "20260216|+|00T308220000|+|204571983650137|+|918036547291084|+|01|+|03|+|84729150|+|39206148|+|001020260822|+",
                "20260218|+|00T108220000|+|563129804782228|+|147095328604371|+|04|+|06|+|21894637|+|78563012|+|001020260822|+",
                "20260217|+|00T206221103|+|780314259680431|+|402615739801526|+|02|+|01|+|90631752|+|53042879|+|001020260822|+",
                "20260220|+|00T108220000|+|319684057123756|+|825074613982041|+|05|+|04|+|13759206|+|67480239|+|001020260822|+",
                "20260219|+|00T308220000|+|095428617305926|+|634891720536840|+|03|+|02|+|46903581|+|05382961|+|001020260822|+",
                "20260222|+|00T108220000|+|641802395746102|+|207568914329675|+|06|+|01|+|75823690|+|12607934|+|001020260822|+",
                "20260221|+|00T108220000|+|827604931578240|+|490352187064516|+|01|+|05|+|39265708|+|85194026|+|001020260822|+",
                "20260224|+|00T508220000|+|105729638402675|+|768301529470318|+|04|+|02|+|58470163|+|24937605|+|001020260822|+",
                "20260223|+|00T108220000|+|476015829340587|+|031946825710963|+|02|+|06|+|91360487|+|60571238|+|001020260822|+",
                "20260226|+|00T408220000|+|358297061485019|+|614073895630287|+|05|+|03|+|02749518|+|40682175|+|001020260822|+",
                "20260225|+|00T308220000|+|709436128057314|+|582901463725630|+|03|+|01|+|56023891|+|73016942|+|001020260822|+",
                "20260227|+|00T108220000|+|234890782228604|+|857410392605173|+|06|+|05|+|89650123|+|19473056|+|001020260822|+",
                "20260228|+|00T408220000|+|461593028782204|+|391028564702381|+|01|+|04|+|73591824|+|50612973|+|001020260822|+",
                "20260301|+|00T206221103|+|915836204759382|+|627403158609425|+|05|+|02|+|26473059|+|81590634|+|001020260822|+",
                "20260302|+|00T108220000|+|380451796208317|+|509372814652018|+|03|+|06|+|90274185|+|46283901|+|001020260822|+",
                "20260303|+|00T508220000|+|726594083165924|+|813047295683740|+|02|+|01|+|58461927|+|37195082|+|001020260822|+",
                "20260304|+|00T108220000|+|149028637502918|+|405918273615094|+|06|+|03|+|83756219|+|06253914|+|001020260822|+",
                "20260305|+|00T308220000|+|593618204857320|+|928047516302815|+|01|+|05|+|41802537|+|72938405|+|001020260822|+",
                "20260306|+|00T108220000|+|865293041726084|+|378220928405137|+|04|+|02|+|60281935|+|95140762|+|001020260822|+",
                "20260307|+|00T408220000|+|207491583609215|+|584630192750368|+|02|+|06|+|53708146|+|19482735|+|001020260822|+",
                "20260308|+|00T108220000|+|738416205973048|+|401529687352190|+|05|+|01|+|90263714|+|56039428|+|001020260822|+",
                "20260309|+|00T608220000|+|419285076314529|+|862530914708356|+|03|+|04|+|15847206|+|73061829|+|001020260822|+",
                "20260310|+|00T308220000|+|605437192860374|+|293847056191042|+|06|+|05|+|39481625|+|05827491|+|001020260822|+",
                "20260311|+|00T108220000|+|082594617350281|+|751930482627035|+|01|+|02|+|46273051|+|80371924|+|001020260822|+",
                "20260312|+|00T508220000|+|730492882210528|+|506283947102584|+|02|+|05|+|39462817|+|71038526|+|001020260822|+",
                "20260313|+|00T108220000|+|318064759283516|+|847210693501728|+|05|+|01|+|62740139|+|40281596|+|001020260822|+",
                "20260314|+|00T206221103|+|964172058460293|+|235719840615382|+|01|+|03|+|81029546|+|57396104|+|001020260822|+",
                "20260315|+|00T108220000|+|405839261713059|+|793058624109418|+|04|+|06|+|51739204|+|64028195|+|001020260822|+",
                "20260318|+|00T408220000|+|271506394825017|+|468392015726093|+|02|+|02|+|39584016|+|80271594|+|001020260822|+",
                "20260319|+|00T108220000|+|824917063501284|+|150462938504716|+|06|+|01|+|61820539|+|39461825|+|001020260822|+",
                "20260320|+|00T408220000|+|573840192640385|+|302795814602359|+|01|+|05|+|42615073|+|94158603|+|001020260822|+",
                "20260321|+|00T108220000|+|906157384529160|+|549310268405137|+|03|+|04|+|73594218|+|06283749|+|001020260822|+",
                "20260322|+|00T308220000|+|152839475603918|+|726409381502716|+|05|+|02|+|84016275|+|31750468|+|001020260822|+",
                "20260325|+|00T108220000|+|493618205713049|+|603827159406258|+|02|+|06|+|56041938|+|90271546|+|001020260822|+"
        );

        // ============ 方法一:集合排序(Collections.sort + 自定义Comparator) ============
        // 排序规则:日期降序、列2降序、列3降序、列4升序、列5升序、列8降序
        log.info("========== 集合排序(Collections.sort)==========");
        List<String> sortedByCollections = new ArrayList<>(pureList);
        Collections.sort(sortedByCollections, (row1, row2) -> {
            int cmp;
            // 列0降序:row2与row1比较,实现降序效果
            cmp = getByIndex(row2, 0).compareTo(getByIndex(row1, 0));
            if (cmp != 0) {
                return cmp;
            }
            // 列2降序
            cmp = getByIndex(row2, 02).compareTo(getByIndex(row1, 02));
            if (cmp != 0) {
                return cmp;
            }
            // 列3降序
            cmp = getByIndex(row2, 03).compareTo(getByIndex(row1, 03));
            if (cmp != 0) {
                return cmp;
            }
            // 列4升序:row1与row2比较,实现升序效果
            cmp = getByIndex(row1, 04).compareTo(getByIndex(row2, 04));
            if (cmp != 0) {
                return cmp;
            }
            // 列5升序
            cmp = getByIndex(row1, 05).compareTo(getByIndex(row2, 05));
            if (cmp != 0) {
                return cmp;
            }
            // 列8降序
            return getByIndex(row2, 8).compareTo(getByIndex(row1, 8));
        });
        sortedByCollections.forEach(row -> log.info("Collections排序: {}", row));

        /**
         * 方法一优缺点分析:
         *
         * 优点:
         * 1. 直观清晰:通过row1和row2的参数交换方式直接表达升序或降序,代码逻辑一目了然
         * 2. 灵活性高:可以在任意比较步骤中加入复杂的业务逻辑判断
         * 3. 性能稳定:不涉及额外的对象创建,内存开销小
         * 4. 精确控制:每个比较步骤都可以精确控制升序/降序,不容易出错
         *
         * 缺点:
         * 1. 代码冗长:每个比较步骤都需要if判断和return语句,代码行数较多
         * 2. 可读性较差:参数交换方式(row2, row1)需要仔细阅读才能理解排序方向
         * 3. 维护成本高:如果需要修改排序规则,需要修改多处代码,容易遗漏
         * 4. 缺乏复用性:排序逻辑内联在lambda中,难以复用和测试
         */


        // ============ 方法二:流排序(Stream.sorted + 链式Comparator) ============
        log.info("========== 流排序(Stream.sorted)==========");
        List<String> sortedByStream = pureList.stream()
                .sorted(Comparator.comparing((String row) -> getByIndex(row, 0)).reversed()
                        .thenComparing(row -> getByIndex(row, 02)).reversed()
                        .thenComparing(row -> getByIndex(row, 03)).reversed()
                        .thenComparing(row -> getByIndex(row, 04))
                        .thenComparing(row -> getByIndex(row, 05))
                        .thenComparing(row -> getByIndex(row, 8)).reversed())
                .collect(Collectors.toList());
        sortedByStream.forEach(row -> log.info("Stream排序: {}", row));

        /**
         * 方法二优缺点分析:
         *
         * 优点:
         * 1. 函数式风格:使用链式调用,代码简洁优雅,符合现代Java编程风格
         * 2. 声明式表达:通过reversed()清晰表达升序/降序意图,可读性强
         * 3. 易于扩展:可以轻松添加更多排序条件,只需链式添加thenComparing
         * 4. 符合最佳实践:充分利用Java 8 Stream API的特性
         * 5. 适合管道处理:可以与其他流操作(filter、map等)无缝集成
         *
         * 缺点:
         * 1. 性能开销:涉及Stream的创建和collect操作,有额外的性能开销
         * 2. 内存消耗:Stream操作过程中可能产生中间对象,内存占用相对较高
         * 3. 调试困难:流式操作的链式调用调试不便,问题定位相对复杂
         * 4. 学习曲线:对不熟悉Stream API的开发者来说,理解成本较高
         * 5. 重复解析:每次比较都调用getByIndex解析字符串,可能存在性能优化空间
         */


        // ============ 方法三:集合排序:Comparator.comparing + reversed ============
        log.info("========== 集合排序:Comparator.comparing + reversed ==========");
        List<String> sortedByComparator = new ArrayList<>(pureList);
        sortedByComparator.sort(Comparator
                .comparing((String row) -> getByIndex(row, 0)).reversed()
                .thenComparing(row -> getByIndex(row, 02)).reversed()
                .thenComparing(row -> getByIndex(row, 03)).reversed()
                .thenComparing(row -> getByIndex(row, 04))
                .thenComparing(row -> getByIndex(row, 05))
                .thenComparing(row -> getByIndex(row, 8)).reversed());
        sortedByComparator.forEach(row -> log.info("Comparator排序: {}", row));

        /**
         * 方法三优缺点分析:
         *
         * 优点:
         * 1. 性能最优:直接在List上排序,避免了Stream的创建和收集操作
         * 2. 代码简洁:链式调用比传统Comparator写法更简洁
         * 3. 表达清晰:通过reversed()方法明确表达排序方向,易于理解
         * 4. 内存高效:不创建额外的中间集合,内存使用效率高
         * 5. 复用性强:可以将Comparator单独提取出来,在不同场景复用
         *
         * 缺点:
         * 1. 类型冗余:需要显式声明(String row)类型参数,略显冗余
         * 2. 重复调用:每次比较都重复调用getByIndex解析字符串
         * 3. 链式深度:多个thenComparing调用可能导致代码行较长
         * 4. 异常处理:Lambda表达式中的异常处理相对复杂
         * 5. 重复解析问题:与方法二一样存在重复解析的性能问题
         */


        // ============ 方法四:集合排序:先正向Comparator再Collections.reverse ============
        log.info("========== 集合排序:先正向Comparator再Collections.reverse ==========");
        List<String> sortedByReverse = new ArrayList<>(pureList);
        sortedByReverse.sort(Comparator
                .comparing((String row) -> getByIndex(row, 0)).reversed()
                .thenComparing(row -> getByIndex(row, 02)).reversed()
                .thenComparing(row -> getByIndex(row, 03)).reversed()
                .thenComparing(row -> getByIndex(row, 04))
                .thenComparing(row -> getByIndex(row, 05))
                .thenComparing(row -> getByIndex(row, 8)).reversed());
        Collections.reverse(sortedByReverse);
        sortedByReverse.forEach(row -> log.info("先升序后Collections.reverse: {}", row));

        /**
         * 方法四优缺点分析:
         *
         * 优点:
         * 1. 简单直观:先按一种规则排序,再整体反转,逻辑容易理解
         * 2. 适合场景:当需要完全反转排序结果时非常方便
         * 3. 易于调试:可以先验证正向排序是否正确,再考虑反转
         *
         * 缺点:
         * 1. 逻辑错误:这是错误的实现方式!混合升序降序的排序规则不能简单反转
         * 2. 结果错误:会导致排序结果完全不符合预期,所有列的排序方向都被反转
         * 3. 性能浪费:额外的Collections.reverse操作增加了时间复杂度
         * 4. 不适用场景:仅适用于全部升序要转为全部降序的简单场景
         * 5. 维护陷阱:容易被误认为是优化的排序方式,实际上会产生错误结果
         *
         * 注意:此方法演示了常见的排序错误,不要在实际代码中使用!
         */


        // ============ 方法五:关键元组法(构建String元组,再倒序) ============
        log.info("========== 集合排序:关键元组法(构建String元组,再倒序) ==========");
        List<String> sortedByTuple = new ArrayList<>(pureList);
        sortedByTuple.sort((row1, row2) -> {
            // 构建正向元组(未使用)
            String tuple1 = getByIndex(row1, 0) + "|" + getByIndex(row1, 02) + "|" + getByIndex(row1, 03)
                    + "|" + getByIndex(row1, 04) + "|" + getByIndex(row1, 05) + "|" + getByIndex(row1, 8);
            String tuple2 = getByIndex(row2, 0) + "|" + getByIndex(row2, 02) + "|" + getByIndex(row2, 03)
                    + "|" + getByIndex(row2, 04) + "|" + getByIndex(row2, 05) + "|" + getByIndex(row2, 8);

            // 构建反向元组(对需要降序的列进行反转)
            String reverseTuple1 = reverseValue(getByIndex(row1, 0)) + "|" + reverseValue(getByIndex(row1, 02)) + "|" + reverseValue(getByIndex(row1, 03))
                    + "|" + getByIndex(row1, 04) + "|" + getByIndex(row1, 05) + "|" + reverseValue(getByIndex(row1, 8));
            String reverseTuple2 = reverseValue(getByIndex(row2, 0)) + "|" + reverseValue(getByIndex(row2, 02)) + "|" + reverseValue(getByIndex(row2, 03))
                    + "|" + getByIndex(row2, 04) + "|" + getByIndex(row2, 05) + "|" + reverseValue(getByIndex(row2, 8));
            return reverseTuple1.compareTo(reverseTuple2);
        });
        sortedByTuple.forEach(row -> log.info("关键元组法: {}", row));

        /**
         * 方法五优缺点分析:
         *
         * 优点:
         * 1. 理论创新:通过字符串反转巧妙实现降序,思路独特
         * 2. 一次比较:将多个列组合成一个字符串进行一次比较,减少多次函数调用
         * 3. 可优化空间:可以预先计算和缓存元组,避免重复解析
         *
         * 缺点:
         * 1. 性能开销:每次比较都需要构建两个元组字符串,包含多次字符串拼接和反转操作
         * 2. 内存浪费:每个元组字符串都需要额外内存,大数据量时内存消耗严重
         * 3. 字符串长度:元组字符串长度取决于列值长度,可能影响比较性能
         * 4. 局限性强:只适用于字符串比较,数值类型需要额外的转换处理
         * 5. 可读性差:通过字符串反转实现降序的逻辑不够直观,难以理解
         * 6. 维护困难:如果列数或排序规则变化,需要修改元组构建逻辑
         * 7. 错误风险:reverseValue函数对null值处理、特殊字符处理等需要额外考虑
         */


        // ============ 方法六:自定义Comparator静态方法封装 ============
        log.info("========== 集合排序:自定义Comparator静态方法封装 ==========");
        List<String> sortedByCustomComparator = new ArrayList<>(pureList);
        sortedByCustomComparator.sort(SortUtils::multiColumnComparatorMixed);
        sortedByCustomComparator.forEach(row -> log.info("自定义Comparator封装: {}", row));

        /**
         * 方法六优缺点分析:
         *
         * 优点:
         * 1. 职责分离:将排序逻辑从业务代码中分离,符合单一职责原则
         * 2. 可测试性强:独立的静态方法便于单元测试和验证
         * 3. 代码复用:Comparator可以在不同场景复用,提高代码复用性
         * 4. 易于维护:排序逻辑集中在一个方法中,修改和维护更方便
         * 5. 性能优化:可以在方法内部添加缓存机制,优化重复解析问题
         * 6. 可读性好:方法名称明确表达排序意图,代码语义清晰
         * 7. 扩展性强:可以通过参数配置不同的排序规则,提高灵活性
         *
         * 缺点:
         * 1. 方法引用限制:使用方法引用时参数和返回值必须严格匹配Comparator接口
         * 2. 调试复杂性:需要跳转到独立方法查看排序逻辑,调试时不够直观
         * 3. 静态方法限制:无法访问实例变量,需要所有数据通过参数传递
         * 4. 重复代码:与lambda方式相比,可能需要更多的样板代码
         * 5. 方法数量:如果排序规则多样化,可能会产生多个Comparator方法
         */
    }

    /**
     * 多列混合排序Comparator
     * 排序规则:日期降序、列2降序、列3降序、列4升序、列5升序、列8降序
     *
     * @param row1 第一行数据
     * @param row2 第二行数据
     * @return 比较结果,负数表示row1小于row2,0表示相等,正数表示row1大于row2
     */
    private static int multiColumnComparatorMixed(String row1, String row2) {
        int cmp;
        // 列0降序
        cmp = getByIndex(row2, 0).compareTo(getByIndex(row1, 0));
        if (cmp != 0) {
            return cmp;
        }
        // 列2降序
        cmp = getByIndex(row2, 02).compareTo(getByIndex(row1, 02));
        if (cmp != 0) {
            return cmp;
        }
        // 列3降序
        cmp = getByIndex(row2, 03).compareTo(getByIndex(row1, 03));
        if (cmp != 0) {
            return cmp;
        }
        // 列4升序
        cmp = getByIndex(row1, 04).compareTo(getByIndex(row2, 04));
        if (cmp != 0) {
            return cmp;
        }
        // 列5升序
        cmp = getByIndex(row1, 05).compareTo(getByIndex(row2, 05));
        if (cmp != 0) {
            return cmp;
        }
        // 列8降序
        return getByIndex(row2, 8).compareTo(getByIndex(row1, 8));
    }

    /**
     * 字符串反转方法,用于关键元组法实现降序排序
     * 通过反转字符串来改变比较结果,实现降序效果
     *
     * @param value 需要反转的字符串
     * @return 反转后的字符串,如果输入为null则返回null
     */
    private static String reverseValue(String value) {
        if (value == null) {
            return null;
        }
        return new StringBuilder(value).reverse().toString();
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值