上周代码分享中的一个代码,因业务需要要将一组数据库自增的id, 思路就是将id排序,取最小的为基数, 取剩下所有数与基数的差值 新建一个数组将差值的下标改为1 其他默认为0 将这个数组 拆分4个一组 转换为16进制 . 压缩效果如下:
压缩后 = 10zd3e9fffffffffffffffffffffffc
ID个数 = 104
解压后 = [10,11,13,16,17,18,19,20,22,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119]
JAVA实现
package com.example.demo.utils;
import cn.hutool.core.util.ArrayUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.LongSummaryStatistics;
import java.util.stream.Collectors;
public final class CompressionIdUtil {
private CompressionIdUtil() {
}
public static final String SEPARATOR = "z";
public static String compression(long... ids) {
if (ArrayUtil.isEmpty(ids)) {
return "";
}
LongSummaryStatistics arrResult = Arrays.stream(ids.clone()).distinct().sorted().summaryStatistics();
long count = arrResult.getCount();
long minId = arrResult.getMin();
if (count == 1) {
return minId + SEPARATOR + 1;
}
long maxId = arrResult.getMax();
long[] newIds = new long[(int) (Math.ceil(Math.max((((int) (maxId - minId)) >> 3) + 1, 1)) * 8)];
Arrays.stream(ids).forEach(id -> newIds[(int) (id - minId)] = 1);
List<String> compressionList = Arrays.stream(newIds).mapToObj(String::valueOf).collect(Collectors.toList());
return minId + SEPARATOR + Lists.partition(compressionList, 4).stream()
.map(item -> Integer.toString(Integer.parseInt(String.join("", item), 2), 16))
.collect(Collectors.joining());
}
public static List<Long> unpack(String compressionStr) {
if (StringUtils.isBlank(compressionStr)) {
return Collections.emptyList();
}
String[] strArr = compressionStr.split(SEPARATOR);
if (strArr.length != 2) {
return Collections.emptyList();
}
String baseId = strArr[0];
char[] chars = strArr[1].toCharArray();
long id = Long.parseLong(baseId);
if (chars.length == 1) {
return Collections.singletonList(id);
}
StringBuilder compression = new StringBuilder();
for (char aChar : chars) {
compression.append(StringUtils.leftPad(Integer.toString(Integer.parseInt(String.valueOf(aChar), 16), 2), 4, "0"));
}
List<Long> resultList = Lists.newArrayListWithCapacity(compressionStr.length() >> 2);
for (int i = 0; i < compression.toString().toCharArray().length; i++) {
if (compression.toString().toCharArray()[i] == '1') {
resultList.add(id + i);
}
}
return resultList;
}
public static void main(String[] args) {
String compression = compression(10, 16, 11, 13, 17, 18, 19, 20, 22, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119);
System.out.println("compression = " + compression);
List<Long> unpack = unpack(compression);
int size = unpack.size();
System.out.println("size = " + size);
String s = JSONObject.toJSONString(unpack);
System.out.println("s = " + s);
}
}
JS实现
const byteToHex = (s) => {
const r = parseInt(s, 2).toString(16);
return r;
};
const hexToByte = (s) => {
const r = parseInt(s, 16).toString(2);
return r;
};
export const arrayToStr = (arr) => {
arr.sort(function (a, b) {
return +a - +b;
});
const baseId = arr[0];
const indexArr = arr.map((o) => +o - +baseId);
const len = +indexArr[indexArr.length - 1] + 1;
const newArr = new Array(Math.ceil(len / 8) * 8).fill(0);
indexArr.forEach((o) => (newArr[+o] = 1));
let strArr = Array(newArr.length / 4)
.fill(0)
.map((o) => (o = newArr.splice(0, 4).join('')));
let data = strArr.map((o) => byteToHex(o)).join('');
return `${data}z${baseId}`;
};
export const strToArray = (s) => {
let baseId = s.substr(s.indexOf('z') + 1);
let strArr = s.substr(0, s.indexOf('z'));
let arr = strArr.split('');
let m = new Array(arr.length).fill(0).map((o) => hexToByte(arr.splice(0, 1)));
let newArr = m
.map((o) => o.padStart(4, '0'))
.join('')
.split('');
let indexArr = [];
newArr.forEach((o, i) => o === '1' && indexArr.push(i));
indexArr = indexArr.map((o) => `${String(+baseId + o)}`);
return indexArr;
};
|