com.xyzwps.lib.dollar.Seq Maven / Gradle / Ivy
Show all versions of xyzwps-dollar Show documentation
package com.xyzwps.lib.dollar;
import com.xyzwps.lib.dollar.function.ObjIntFunction;
import com.xyzwps.lib.dollar.function.ObjIntPredicate;
import java.util.*;
import java.util.function.*;
import static com.xyzwps.lib.dollar.Dollar.*;
import static com.xyzwps.lib.dollar.Helper.*;
/**
* 操作符应该分 3 类
* 1. 收集一个就可以干活,比如 map、filter
* 2. 收集一些才能干活,比如 chunk
* 3. 收集全部才能干活,比如 groupBy、orderBy、reverse
*
* TODO: 实现 index 版本
*
* @param
*/
public interface Seq extends Iterable {
void forEach(Consumer consumer);
default void forEach(ObjIntConsumer consumer) {
Objects.requireNonNull(consumer);
Counter counter = new Counter(0);
this.forEach(t -> consumer.accept(t, counter.getAndIncr()));
}
default Seq map(Function mapFn) {
Objects.requireNonNull(mapFn);
return rConsumer -> this.forEach(t -> rConsumer.accept(mapFn.apply(t)));
}
default Seq map(ObjIntFunction mapFn) {
Objects.requireNonNull(mapFn);
Counter counter = new Counter(0);
return rConsumer -> this.forEach(t -> rConsumer.accept(mapFn.apply(t, counter.getAndIncr())));
}
default Seq filter(Predicate predicate) {
Objects.requireNonNull(predicate);
return tConsumer -> this.forEach(t -> {
if (predicate.test(t)) {
tConsumer.accept(t);
}
});
}
default Seq filter(ObjIntPredicate predicate) {
Objects.requireNonNull(predicate);
Counter counter = new Counter(0);
return tConsumer -> this.forEach(t -> {
if (predicate.test(t, counter.getAndIncr())) {
tConsumer.accept(t);
}
});
}
default Seq flatMap(Function> flatMapFn) {
return rConsumer -> this.forEach(t -> {
Seq rSeq = flatMapFn.apply(t);
if (rSeq != null) {
rSeq.forEach(rConsumer);
}
});
}
default Seq> chunk(final int chunkSize) {
if (chunkSize < 1) {
throw new IllegalArgumentException("Each chunk should have at least one element.");
}
// TODO: 优化
class ChunkEnv {
List list = new ArrayList<>(chunkSize);
int count = 0;
boolean add(T t) {
this.list.add(t);
this.count++;
return this.count == chunkSize;
}
List getAndClean() {
List result = this.list;
this.list = new ArrayList<>(chunkSize);
this.count = 0;
return result;
}
}
return listConsumer -> {
ChunkEnv env = new ChunkEnv();
this.forEach(t -> {
if (env.add(t)) {
listConsumer.accept(env.getAndClean());
}
});
if (env.count > 0) {
listConsumer.accept(env.getAndClean());
}
};
}
default Seq compact() {
return this.filter(t -> !$.isFalsey(t));
}
default Seq concat(Iterable seq2) {
if (seq2 == null) return this;
return tConsumer -> {
this.forEach(tConsumer);
seq2.forEach(tConsumer);
};
}
default Seq take(final int n) {
if (n < 1) {
throw new IllegalArgumentException("You should take at least one element.");
}
return StopException.stop(tConsumer -> {
Counter counter = new Counter(0);
this.forEach(t -> {
if (counter.getAndIncr() < n) {
tConsumer.accept(t);
}
if (counter.get() >= n) {
throw new StopException();
}
});
});
}
default Seq takeWhile(Predicate predicate) {
Objects.requireNonNull(predicate);
return StopException.stop(tConsumer -> {
this.forEach(t -> {
if (predicate.test(t)) {
tConsumer.accept(t);
} else {
throw new StopException();
}
});
});
}
default Seq skip(int n) {
return tConsumer -> {
int[] counter = {0};
this.forEach(t -> {
if (counter[0] < n) {
counter[0]++;
} else {
tConsumer.accept(t);
}
});
};
}
default Seq skipWhile(Predicate predicate) {
return tConsumer -> {
boolean[] next = {true};
this.forEach(t -> {
next[0] = next[0] && predicate.test(t);
if (!next[0]) {
tConsumer.accept(t);
}
});
};
}
default Optional first() {
Holder holder = new Holder<>(null);
StopException.stop(() -> this.forEach(t -> {
holder.value = t;
throw new StopException();
}));
return Optional.ofNullable(holder.value);
}
default Optional head() {
return this.first();
}
default R reduce(R initValue, BiFunction reducer) {
Holder rHolder = new Holder<>(initValue);
this.forEach(t -> rHolder.value = reducer.apply(rHolder.value, t));
return rHolder.value;
}
default Seq reverse() {
ArrayList list = this.toList();
ArrayListReverseIterator itr = new ArrayListReverseIterator<>(list);
return tConsumer -> {
while (itr.hasNext()) tConsumer.accept(itr.next());
};
}
@Override
default Iterator iterator() {
List list = this.toList();
return list.iterator();
}
default > Seq orderBy(Function toKey, Direction direction) {
Objects.requireNonNull(toKey);
Objects.requireNonNull(direction);
ArrayList list = this.toList();
Comparator comparator = direction == Direction.DESC ? descComparator(toKey) : ascComparator(toKey);
list.sort(comparator);
return list::forEach;
}
default Seq zip(Iterable iterable, BiFunction zipper) {
Objects.requireNonNull(zipper);
if (iterable == null) {
return this.map(t -> zipper.apply(t, null));
}
Iterator itr = iterable.iterator();
return rConsumer -> {
this.forEach(t -> rConsumer.accept(zipper.apply(t, itr.hasNext() ? itr.next() : null)));
while (itr.hasNext()) {
rConsumer.accept(zipper.apply(null, itr.next()));
}
};
}
default Seq> zip(Iterable iterable) {
return this.zip(iterable, Pair::of);
}
default MESeq> groupBy(Function toKey) {
Objects.requireNonNull(toKey);
Map> map = new HashMap<>();
this.forEach(t -> map.computeIfAbsent(toKey.apply(t), k -> new ArrayList<>()).add(t));
return map::forEach;
}
default MESeq keyBy(Function toKey) {
Objects.requireNonNull(toKey);
Map map = new HashMap<>();
this.forEach(t -> map.computeIfAbsent(toKey.apply(t), k -> t));
return map::forEach;
}
default Seq uniqueBy(Function toKey) {
Objects.requireNonNull(toKey);
Set set = new HashSet<>();
return tConsumer -> {
this.forEach(t -> {
K key = toKey.apply(t);
if (set.contains(key)) {
return;
}
set.add(key);
tConsumer.accept(t);
});
};
}
default Seq unique() {
Set set = new HashSet<>();
return tConsumer -> {
this.forEach(t -> {
if (set.contains(t)) {
return;
}
set.add(t);
tConsumer.accept(t);
});
};
}
default String join(String sep) {
// TODO: 检查 seq
return this.reduce(new StringJoiner(sep), (joiner, t) -> {
joiner.add(t == null ? null : t.toString());
return joiner;
}).toString();
}
default HashSet toSet() {
return this.reduce(new HashSet<>(), (set, t) -> {
set.add(t);
return set;
});
}
default ArrayList toList() {
return this.reduce(new ArrayList<>(), (list, t) -> {
list.add(t);
return list;
});
}
static Seq empty() {
return tConsumer -> {
};
}
default List value() {
return this.toList();
}
}