Java
环境
JDK-8
采用双for
循环,同时得出交集、差集。不依赖Set
、Map
特性,减少内存浪费。
当交集量较大时,可将diffRight = new ArrayList<>()
改为链表diffRight = new LinkedList<>()
,以提高remove
操作性能。改造方式,自由发挥。
Class
Coll.java
import static java.util.stream.Collectors.toList;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* 集合去重
* @author Liu
* @date 2022-9-6 16:11:17
*/
public class Coll {
/**
* @see {@link #sieve(Collection, Collection, BiPredicate)}
*/
@SuppressWarnings("unlikely-arg-type")
public static <L, R> Union<L, R> sieve(Collection<L> left, Collection<R> right) {
return sieve(left, right, L::equals);
}
/**
* @see {@link #sieve(Collection, Collection, BiPredicate, BiFunction, Function)}
*/
public static <L, R> Union<L, R> sieve(Collection<L> left, Collection<R> right, BiPredicate<L, R> eq) {
if (eq == null) {
return sieve(left, right);
}
return sieve(left, right, eq, l -> {});
}
/**
* @see {@link #sieve(Collection, Collection, BiPredicate, BiFunction, Function)}
*/
public static <L, R> Union<L, R> sieve(Collection<L> left, Collection<R> right,
BiPredicate<L, R> eq,
Consumer<L> fit) {
return sieve(left, right, eq, (l, r) -> fit.accept(l));
}
/**
* @see {@link #sieve(Collection, Collection, BiPredicate, BiFunction, Function)}
*/
public static <L, R> Union<L, R> sieve(Collection<L> left, Collection<R> right,
BiPredicate<L, R> eq,
BiConsumer<L, R> fit) {
return sieve(left, right, eq, (l, r) -> {
fit.accept(l, r);
return true;
}, Function.identity());
}
/**
* 筛选(Lambda)
* @param left {@link Collection}<{@link L}>:左集;
* @param right {@link Collection}<{@link L}>:右集;
* @param fit {@link BiConsumer}<{@link L}, {@link L}>:对{@code eq}符合条件的元素操作,并返回{@code boolean}值,表示是否添加到{@link Union#intersect};
* @param eqs {@link Function}<{@link L}, ?>[]:多个筛选条件的平铺写法。
* <i>默认:{@link Object#equals(Object)}</i>
* <ul>例如:
* <li>{@link java.time.LocalDate}::getYear, {@link java.time.LocalDate}::getMonth</li>
* </ul>;
* @return {@link Union}<{@link L}, {@link L}>:筛选结果;
* @author Liu
* @date 2022-9-6 16:11:17
* @see {@link #sieve(Collection, Collection, BiPredicate, BiFunction, Function)}
*/
@SafeVarargs
public static <L> Union<L, L> sieve(Collection<L> left, Collection<L> right,
BiConsumer<L, L> fit,
Function<L, ?>... eqs) {
return sieve(left, right, (l, r) -> {
for (int i = 0; i < eqs.length; i++) {
Function<L, ?> eq = eqs[i];
Object lv = eq.apply(l);
Object rv = eq.apply(r);
if (!lv.equals(rv)) {
return false;
}
}
return true;
}, (l, r) -> {
fit.accept(l, r);
return true;
}, Function.identity());
}
/**
* @see {@link #sieve(Collection, Collection, BiPredicate, BiFunction, Function)}
*/
public static <L, R> Union<L, R> sieve(Collection<L> left, Collection<R> right,
BiPredicate<L, R> eq,
Predicate<L> fit) {
return sieve(left, right, eq, (l, r) -> fit.test(l), Function.identity());
}
/**
* 筛选(Lambda)
* @param left {@link Collection}<{@link L}>:左集;
* @param right {@link Collection}<{@link R}>:右集;
* @param eq {@link BiPredicate}<{@link L}, {@link R}>:筛选条件,判断相同的条件。<i>默认:{@link Object#equals(Object)}</i>;
* @param fit {@link BiPredicate}<{@link L}, {@link R}>:对{@code eq}符合条件的元素操作,并返回{@code boolean}值,表示是否添加到{@link Union#intersect};
* @param diffLeft {@link Function}<{@link L}, {@link L}>:对{@link Union#diffLeft}左差集元素操作;
* @return {@link Union}<{@link L}, {@link R}>:筛选结果;
* @author Liu
* @date 2022-9-6 16:11:17
* @see {@link #sieve(Collection, Collection, Sieve)}
*/
@SuppressWarnings("unlikely-arg-type")
public static <L, R> Union<L, R> sieve(Collection<L> left, Collection<R> right,
BiPredicate<L, R> eq,
BiPredicate<L, R> fit,
Function<L, L> diffLeft) {
if (eq == null) {
eq = L::equals;
}
BiPredicate<L, R> equal = eq;
return sieve(left, right, new Sieve<L, R>() {
@Override
public boolean eq(L left, R right) {
return equal.test(left, right);
}
@Override
public boolean fit(L left, R right, int i) {
return fit.test(left, right);
}
@Override
public L diffLeft(L left) {
return diffLeft.apply(left);
}
});
}
/**
* 筛选
* @param left {@link Collection}<{@link L}>:左集;
* @param right {@link Collection}<{@link R}>:右集;
* @param sieve {@link Sieve}<{@link L}, {@link R}>:筛选器;
* @return {@link Union}<{@link L}, {@link R}>:筛选结果;
* @author Liu
* @date 2022-9-6 16:11:17
*/
public static <L, R> Union<L, R> sieve(Collection<L> left, Collection<R> right, Sieve<L, R> sieve) {
Union<L, R> union = new Union<>();
if (left == null || left.isEmpty()) {
return union.setDiffRight(right);
}
if (right == null || right.isEmpty()) {
return union.setDiffLeft(left);
}
List<R> diffRight = new ArrayList<>(right);
List<L> diffLeft = new ArrayList<>(left.size());
union.setDiffRight(diffRight).setDiffLeft(diffLeft);
@SuppressWarnings("unchecked")
Sieve<L, R> si = sieve != null ? sieve : (Sieve<L, R>) Sieve.SIEVE;
List<L> intersect = left.stream().filter(le -> {
for (int i = 0; i < diffRight.size(); i++) {
R ri = diffRight.get(i);
if (si.eq(le, ri)) {
return si.fit(le, diffRight.remove(i--), i);
}
}
diffLeft.add(si.diffLeft(le));
return false;
}).collect(toList());
return union.setIntersect(intersect);
}
/**
* 汇集结果
* @param <L>:左集类型;
* @param <R>:右集类型;
* @author Liu
* @date 2022-9-6 16:11:17
*/
public static class Union<L, R> implements Serializable {
private static final long serialVersionUID = -5870745947717525652L;
/**
* 交集
*/
private Collection<L> intersect = Collections.emptyList();
/**
* 左差集
*/
private Collection<L> diffLeft = Collections.emptyList();
/**
* 右差集
*/
private Collection<R> diffRight = Collections.emptyList();
public Union() {
super();
}
public Union(Collection<L> intersect, Collection<L> diffLeft, Collection<R> diffRight) {
this();
this.setIntersect(intersect).setDiffLeft(diffLeft).setDiffRight(diffRight);
}
/**
* 交集
*/
public Collection<L> getIntersect() {
return intersect;
}
public Union<L, R> setIntersect(Collection<L> intersect) {
this.intersect = intersect != null ? intersect : this.intersect;
return this;
}
/**
* 左差集
*/
public Collection<L> getDiffLeft() {
return diffLeft;
}
public Union<L, R> setDiffLeft(Collection<L> diffLeft) {
this.diffLeft = diffLeft != null ? diffLeft : this.diffLeft;
return this;
}
/**
* 右差集
*/
public Collection<R> getDiffRight() {
return diffRight;
}
public Union<L, R> setDiffRight(Collection<R> diffRight) {
this.diffRight = diffRight != null ? diffRight : this.diffRight;
return this;
}
@Override
public String toString() {
return "{intersect: " + intersect + ",\r\ndiffLeft: " + diffLeft + ",\r\ndiffRight: " + diffRight + "}";
}
}
/**
* 筛选功能器
* @author Liu
* @date 2022-9-6 17:20:23
*/
public static interface Sieve<L, R> {
Sieve<Object, Object> SIEVE = new Sieve<Object, Object>() {};
/**
* 筛选条件,判断为相同的条件
* @param left {@link L}:左集元素;
* @param right {@link R}:右集元素;
* @return {@link Boolean}:两元素是否匹配;
* @see {@link Object#equals(Object)}
*/
@SuppressWarnings("unlikely-arg-type")
default boolean eq(L left, R right) {
return left.equals(right);
}
/**
* 符合元素
* @param left {@link L}:左集匹配元素;
* @param right {@link R}:右集被移除的匹配元素;
* @param i int:索引;
* @return {@link Boolean}:是否加入交集;
*/
default boolean fit(L left, R right, int i) {
return true;
}
/**
* 交集元素
*/
// default L intersect(L intersect) {
// return intersect;
// }
/**
* 右差集元素
*/
// default R diffRight(R diffRight) {
// return diffRight;
// }
/**
* 左差集元素
*/
default L diffLeft(L left) {
return left;
}
}
}
并集 = 交集 + 左差集 + 右差集
测试示例
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Arrays;
import java.util.List;
import java.util.function.BiConsumer;
/**
* 测试去重
* @author Liu
* @date 2022-9-6 16:11:17
*/
public class Test {
public static void main(String[] args) {
List<LocalDate> dtl = Arrays.asList(
LocalDate.of(2022, 10, 1),
LocalDate.of(2022, 9, 2),
LocalDate.of(2022, 9, 6),
LocalDate.of(2022, 9, 28)
);
List<LocalDate> dtr = Arrays.asList(
LocalDate.of(2022, 9, 1),
LocalDate.of(2022, 9, 2),
LocalDate.of(2022, 9, 6)
);
/* 以 右集合 为基准数据 */
Union<LocalDate, LocalDate> dt = Coll.sieve(dtl, dtr);
System.out.println("相同 - Update:\t" + dt.getIntersect());
System.out.println("新增 - Insert:\t" + dt.getDiffLeft());
System.out.println("删除 - Delete:\t" + dt.getDiffRight());
System.out.println();
List<LocalTime> tml = Arrays.asList(
LocalTime.of(0, 59, 59),
LocalTime.of(0, 0),
LocalTime.of(0, 0, 1),
LocalTime.of(1, 0)
);
List<LocalTime> tmr = Arrays.asList(
LocalTime.of(0, 0),
LocalTime.of(0, 0, 1),
LocalTime.of(0, 6)
);
LocalDate atDate = LocalDate.of(2022, 10, 1);
List<LocalDateTime> dtms = new java.util.ArrayList<>(3);
BiConsumer<LocalTime, LocalTime> fit = (l, r) -> dtms.add(l.atDate(atDate)); // 对相同的元素,做其它操作
Union<LocalTime, LocalTime> tm = Coll.sieve(tml, tmr, fit, LocalTime::getHour, LocalTime::getMinute); // 时分相等,则视为相同
System.out.println("相同 - Update:\t" + tm.getIntersect());
System.out.println("新增 - Insert:\t" + tm.getDiffLeft());
System.out.println("删除 - Delete:\t" + tm.getDiffRight());
System.out.println(dtms);
System.out.println();
List<LocalDateTime> dtml = Arrays.asList(
LocalDateTime.of(LocalDate.of(2022, 10, 1), LocalTime.MIN),
LocalDateTime.of(LocalDate.of(2022, 9, 2), LocalTime.MIN),
LocalDateTime.of(LocalDate.of(2020, 9, 6), LocalTime.MIN),
LocalDateTime.of(LocalDate.of(2022, 9, 28), LocalTime.MIN)
);
List<LocalDateTime> dtmr = Arrays.asList(
LocalDateTime.of(LocalDate.of(2022, 9, 1), LocalTime.MIN),
LocalDateTime.of(LocalDate.of(2022, 9, 2), LocalTime.MIN),
LocalDateTime.of(LocalDate.of(2020, 9, 6), LocalTime.MIN)
);
Union<LocalDateTime, LocalDateTime> dtUn = Coll.sieve(dtml, dtmr,
(l, r) -> l.toLocalDate().equals(r.toLocalDate()),
(l, r) -> !l.toLocalDate().isLeapYear(), // 闰年不添加到并集
l -> l.plusHours(8)
);
System.out.println("相同 - Update:\t" + dtUn.getIntersect());
System.out.println("新增 - Insert:\t" + dtUn.getDiffLeft());
System.out.println("删除 - Delete:\t" + dtUn.getDiffRight());
System.out.println();
List<LocalDate> datel = Arrays.asList(
LocalDate.of(2022, 10, 1),
LocalDate.of(2022, 9, 2),
LocalDate.of(2022, 9, 6),
LocalDate.of(2022, 9, 28)
);
List<LocalTime> timer = Arrays.asList(
LocalTime.of(0, 0),
LocalTime.of(0, 0, 1),
LocalTime.of(0, 6)
);
Union<LocalDate, LocalTime> dtm = Coll.sieve(datel, timer, (l, r) -> l.getDayOfMonth() == r.getSecond());
System.out.println("相同 - Update:\t" + dtm.getIntersect());
System.out.println("新增 - Insert:\t" + dtm.getDiffLeft());
System.out.println("删除 - Delete:\t" + dtm.getDiffRight());
System.out.println();
}
}
JavaScript、NodeJS
环境
需支持ES6
代码
/**
* 筛选功能器
*/
function Sieve() {}
(function () {
let sieve;
/**
* 判断相同的条件
* @return {@link boolean}
*/
Sieve.prototype.eq = (left, right) => left == right;
/**
* 是否将符合的元素加入交集
* @return {@link boolean}:true - 加入。
*/
Sieve.prototype.fit = (left, right, i) => true;
/**
* 左差集元素
* @return {@link Object}:转换结果。
*/
Sieve.prototype.diffLeft = left => left;
/**
* 筛选
* @param left {@link Array}:左集;
* @param right {@link Array}:右集;
* @return {@link Union}:筛选结果;
*/
Sieve.prototype.sieve = function (left, right) {
let union = new Union();
if (!left) {
return union.setDiffRight(right);
}
if (!right) {
return union.setDiffLeft(left);
}
let diffRight = [...right];
let diffLeft = [];
union.setDiffRight(diffRight).setDiffLeft(diffLeft);
const intersect = left.filter(le => {
for (let i = 0; i < diffRight.length; i++) {
if (this.eq(le, diffRight[i])) {
return this.fit(le, diffRight.splice(i, 1)[0], i);
}
}
diffLeft.push(this.diffLeft(le));
return false;
})
return union.setIntersect(intersect);
}
/**
* 单例
*/
Sieve.newInstance = () => (sieve = sieve || new Sieve());
})()
/**
* 汇集结果
* @param intersect {@link Array}:交集;
* @param diffLeft {@link Array}:左差集;
* @param diffRight {@link Array}:右差集;
*/
function Union(intersect, diffLeft, diffRight) {
return this.setIntersect(intersect).setDiffLeft(diffLeft).setDiffRight(diffRight);
}
(function(cla) {
cla.prototype.getIntersect = function () {
return (this.intersect ||= [])
}
cla.prototype.getDiffLeft = function () {
return (this.diffLeft ||= [])
}
cla.prototype.getDiffRight = function () {
return (this.diffRight ||= [])
}
cla.prototype.setIntersect = function (intersect) {
this.intersect = intersect;
return this;
}
cla.prototype.setDiffLeft = function (diffLeft) {
this.diffLeft = diffLeft;
return this;
}
cla.prototype.setDiffRight = function (diffRight) {
this.diffRight = diffRight;
return this;
}
})(Union)
测试示例
let le = [ 0, 3, 5, '6', 7, 9 ];
let ri = [ 2, false, 6, 8, 9 ];
let un = Sieve.newInstance().sieve(le, ri);
console.log(un);
/*
intersect: [ 0, '6', 9 ],
diffLeft: [ 3, 5, 7 ],
diffRight: [ 2, 8 ]
*/
使用过程中,如出现bug,或有其它优化建议,欢迎在此文章“评论区”留言讨论,并留下您的邮箱,以便改正后及时通知您。