如何在java中以惰性方式连接两个集合?
我有两个集合,我想返回一个IEnumerable,它是它们的串联。返回的枚举应该是惰性的,不应该修改两个初始集合(因此,我不想将两个集合复制到一个集合中,然后返回结果,因为这不是惰性的) 下面的代码是我想用Java实现但用c#编写的一个示例:如何在java中以惰性方式连接两个集合?,java,lazy-loading,iterable,enumerable,Java,Lazy Loading,Iterable,Enumerable,我有两个集合,我想返回一个IEnumerable,它是它们的串联。返回的枚举应该是惰性的,不应该修改两个初始集合(因此,我不想将两个集合复制到一个集合中,然后返回结果,因为这不是惰性的) 下面的代码是我想用Java实现但用c#编写的一个示例: 公共静态IEnumerable all() { List list1=新列表(){1,2,3}; List list2=新列表(){4,5,6}; 返回列表1.Concat(列表2); } 您可以使用以下方法: 将提供的iterable合并为单个itera
公共静态IEnumerable all()
{
List list1=新列表(){1,2,3};
List list2=新列表(){4,5,6};
返回列表1.Concat(列表2);
}
您可以使用以下方法:
将提供的iterable合并为单个iterable
返回的iterable有一个迭代器,它按照参数的顺序遍历元素,即iterables[0],iterables直到必要时才轮询源迭代器。
或方法:
将多个iterable合并为一个iterable。返回的iterable有一个迭代器,它遍历输入中每个iterable的元素在必要时才轮询输入迭代器。
与
C#IEnumerable Enumerable.Concat(IEnumerable, 数不清)代码>可以在公共集合中找到:Iterable IterableUtils.chaineditable(Iterable这里有一个手动实现,返回一个迭代器
public static <T> Iterator<T> concatIterator(Iterable<T> l1, Iterable<T> l2) {
return new Iterator<>() {
Iterator<T> it1 = l1.iterator();
Iterator<T> it2 = l2.iterator();
public boolean hasNext() {
return it1.hasNext() || it2.hasNext();
}
public T next() {
return it1.hasNext() ? it1.next() : it2.next();
}
}
}
公共静态迭代器concatIterator(Iterable l1,Iterable l2){
返回新的迭代器(){
迭代器it1=l1.Iterator();
迭代器it2=l2.Iterator();
公共布尔hasNext(){
返回it1.hasNext()| it2.hasNext();
}
公共交通工具{
返回it1.hasNext()?it1.next():it2.next();
}
}
}
你可以用它得到一个Iterable
public static <T> Iterable<T> concatIterable(Iterable<T> l1, Iterable<T> l2) {
return new Iterable<>() {
public Iterator<T> iterator() {
return concatIterator(l1, l2);
}
}
}
public static Iterable concaterable(Iterable l1,Iterable l2){
返回新的Iterable(){
公共迭代器迭代器(){
返回计数器(l1,l2);
}
}
}
如果您只需要Iterable
,那么简单的链应该适合您
class Chain<T> implements Iterable<T> {
final Iterable<Iterable<T>> lists;
public Chain(Iterable<T>... lists) {
this.lists = Arrays.asList(lists);
}
@Override
public Iterator<T> iterator() {
return new Iterator<T>() {
// Walks the lists.
Iterator<Iterable<T>> i = lists.iterator();
// Walks the list.
Iterator<T> l = prime(i.hasNext() ? i.next().iterator() : null);
@Override
public boolean hasNext() {
return l != null && l.hasNext();
}
@Override
public T next() {
if (hasNext()) {
T next = l.next();
l = prime(l);
return next;
} else {
throw new NoSuchElementException("Chain exhausted.");
}
}
private Iterator<T> prime(Iterator<T> l) {
// Prepare for next time.
while (l != null && !l.hasNext()) {
if (i.hasNext()) {
l = i.next().iterator();
} else {
l = null;
}
}
return l;
}
};
}
}
public void test(String[] args) {
Chain<Integer> chain = new Chain<>(
Arrays.asList(),
Arrays.asList(1, 2, 3),
Arrays.asList(),
Arrays.asList(4, 5, 6),
Arrays.asList(7,8,9,10),
Arrays.asList()
);
for (Integer i : chain) {
System.out.println(i);
}
}
类链实现了Iterable{
最终可编辑列表;
公共链(Iterable…列表){
this.lists=Arrays.asList(列表);
}
@凌驾
公共迭代器迭代器(){
返回新的迭代器(){
//浏览列表。
迭代器i=lists.Iterator();
//走在名单上。
迭代器l=prime(i.hasNext()?i.next()。迭代器():null);
@凌驾
公共布尔hasNext(){
返回l!=null&&l.hasNext();
}
@凌驾
公共交通工具{
if(hasNext()){
T next=l.next();
l=素数(l);
下一步返回;
}否则{
抛出新的NoSuchElementException(“链耗尽”);
}
}
专用迭代器素数(迭代器l){
//为下次做准备。
while(l!=null&&!l.hasNext()){
if(i.hasNext()){
l=i.next().iterator();
}否则{
l=零;
}
}
返回l;
}
};
}
}
公共无效测试(字符串[]args){
链=新链(
Arrays.asList(),
数组。asList(1,2,3),
Arrays.asList(),
数组。asList(4,5,6),
数组。asList(7,8,9,10),
Arrays.asList()
);
for(整数i:链){
系统输出打印LN(i);
}
}
您还可以对列表
执行类似的工作,甚至可能对集合
执行类似的工作。如果您的输入是列表,则链接列表
下面的类可以对其进行包装
我必须将两个列表作为一个惰性列表提供给JAXB Marshaller,但它不适用于Iterable
。要使用maxOccurs=“unbounded”
JAXB创建元素,需要bean属性至少实现java.util.Collection
该解决方案使用Apache Commons,但在Guava中有一个等价的Iterables.concat()
import org.apache.commons.collections4.iterabluetils;
/**该类使多个列表在调用方看来像一个列表*/
public class/*NOSONAR*/ChainedList扩展了AbstractList实现了随机访问{
私人最终清单[]要素;
私有最终int[]endindex;
@安全变量
公共链接列表(最终列表…列表){
这个(Arrays.asList(lists));
}
@抑制警告(“未选中”)
public ChainedList(最终Iterable元素){
最终列表tmpElementsList=iterabluetils.toList(元素);
this.elements=tmpElementsList.toArray(新列表[tmpElementsList.size()]);
endIndexes=newint[this.elements.length];
int currentSize=0;
for(int i=0;i=大小()时引发
最终列表子列表=元素[partitionIndex];
//当索引为负数或最后一个子列表为空时引发
返回子列表.get(子索引);
}
@凌驾
公共E集(最终整数索引,最终E元素){
最终int partitionIndex=getPartitionIndex(索引);
最终int子索引=getSubIndex(分区索引,索引);
//当索引>=大小()时引发
最终列表子列表=元素[partitionIndex];
if(子索引<0 | | su
class Chain<T> implements Iterable<T> {
final Iterable<Iterable<T>> lists;
public Chain(Iterable<T>... lists) {
this.lists = Arrays.asList(lists);
}
@Override
public Iterator<T> iterator() {
return new Iterator<T>() {
// Walks the lists.
Iterator<Iterable<T>> i = lists.iterator();
// Walks the list.
Iterator<T> l = prime(i.hasNext() ? i.next().iterator() : null);
@Override
public boolean hasNext() {
return l != null && l.hasNext();
}
@Override
public T next() {
if (hasNext()) {
T next = l.next();
l = prime(l);
return next;
} else {
throw new NoSuchElementException("Chain exhausted.");
}
}
private Iterator<T> prime(Iterator<T> l) {
// Prepare for next time.
while (l != null && !l.hasNext()) {
if (i.hasNext()) {
l = i.next().iterator();
} else {
l = null;
}
}
return l;
}
};
}
}
public void test(String[] args) {
Chain<Integer> chain = new Chain<>(
Arrays.asList(),
Arrays.asList(1, 2, 3),
Arrays.asList(),
Arrays.asList(4, 5, 6),
Arrays.asList(7,8,9,10),
Arrays.asList()
);
for (Integer i : chain) {
System.out.println(i);
}
}
import org.apache.commons.collections4.IterableUtils;
/** This class makes multiple lists look like one to the caller. */
public class /* NOSONAR */ ChainedList<E> extends AbstractList<E> implements RandomAccess {
private final List<E>[] elements;
private final int[] endIndexes;
@SafeVarargs
public ChainedList(final List<E>... lists) {
this(Arrays.asList(lists));
}
@SuppressWarnings("unchecked")
public ChainedList(final Iterable<List<E>> elements) {
final List<List<E>> tmpElementsList = IterableUtils.toList(elements);
this.elements = tmpElementsList.toArray(new List[tmpElementsList.size()]);
endIndexes = new int[this.elements.length];
int currentSize = 0;
for (int i = 0; i < this.elements.length; i++) {
final List<E> curr = this.elements[i];
final int sz = curr.size();
endIndexes[i] = currentSize + sz;
currentSize += sz;
}
}
@Override
public E get(final int index) {
final int partitionIndex = getPartitionIndex(index);
final int subIndex = getSubIndex(partitionIndex, index);
// throws when index >= size()
final List<E> subList = elements[partitionIndex];
// throws when index is negative or last sublist is empty
return subList.get(subIndex);
}
@Override
public E set(final int index, final E element) {
final int partitionIndex = getPartitionIndex(index);
final int subIndex = getSubIndex(partitionIndex, index);
// throws when index >= size()
final List<E> subList = elements[partitionIndex];
if (subIndex < 0 || subIndex >= subList.size()) {
// a sublist may throw unsupported even when index OOB
throw new IndexOutOfBoundsException();
}
return subList.set(subIndex, element);
}
@Override
public Iterator<E> iterator() {
// this may perform better with contained LinkedList
return IterableUtils.chainedIterable(elements).iterator();
}
@Override
public ListIterator<E> listIterator(final int index) {
// indexOf, lastIndexOf, equals, removeRange, subList
// call this method and for non-RandomAccess lists
// the default implementation is slow
// T O D O: implement LazyListIteratorChain similar to
// org.apache.commons.collections4.iterators.LazyIteratorChain
for (final List<E> subList : elements) {
if (!(subList instanceof RandomAccess)) {
throw new UnsupportedOperationException(
"Not RandomAccess: " + subList.getClass().getName());
}
}
return super.listIterator(index);
}
/**
* @return negative value when {@code index} is negative
*/
private int getSubIndex(final int partitionIndex, final int index) {
return index - (partitionIndex == 0 ? 0 : endIndexes[partitionIndex - 1]);
}
private int getPartitionIndex(final int index) {
int location = Arrays.binarySearch(endIndexes, index);
if (location < 0) {
location = (~location) - 1;
}
return location + 1;
}
@Override
public int size() {
return endIndexes.length == 0 ? 0 : endIndexes[endIndexes.length - 1];
}
}