在我的应用程序中,我使用第三方库(确切地说就是MongoDB的Spring Data)。
此库的方法返回Iterable<T>
,而我的其余代码需要Collection<T>
。
是否有任何实用方法可以让我快速将一个转换为另一个?我想避免在我的代码中为这么简单的事情创建一堆foreach
循环。
答案 0 :(得分:357)
使用Guava,您可以使用Lists.newArrayList(Iterable)或Sets.newHashSet(Iterable)以及其他类似方法。这当然会将所有元素复制到内存中。如果这是不可接受的,我认为使用这些代码的代码应该采用Iterable
而不是Collection
。 Guava也恰好使用Collection
(例如Iterable
或Iterables.isEmpty(Iterable)
)在Iterables.contains(Iterable, Object)
上做一些方便的事情,但性能影响更明显
答案 1 :(得分:311)
在JDK 8中,不依赖于其他库:
Using reader As IO.StreamReader = IO.File.OpenText("\\10.31.42.249\share\file.txt") ...
编辑:上面的内容适用于Iterator<T> source = ...;
List<T> target = new ArrayList<>();
source.forEachRemaining(target::add);
。如果您正在处理Iterator
,
Iterable
答案 2 :(得分:86)
您也可以为此编写自己的实用程序方法:
public static <E> Collection<E> makeCollection(Iterable<E> iter) {
Collection<E> list = new ArrayList<E>();
for (E item : iter) {
list.add(item);
}
return list;
}
答案 3 :(得分:67)
使用java.util.stream
的简洁Java 8解决方案:
public static <T> List<T> toList(final Iterable<T> iterable) {
return StreamSupport.stream(iterable.spliterator(), false)
.collect(Collectors.toList());
}
答案 4 :(得分:44)
commons-collections
的 IteratorUtils
可能有所帮助(尽管他们不支持最新稳定版本3.2.1中的泛型):
@SuppressWarnings("unchecked")
Collection<Type> list = IteratorUtils.toList(iterable.iterator());
4.0版(目前在SNAPSHOT中)支持泛型,你可以摆脱@SuppressWarnings
。
更新:从IterableAsList
检查Cactoos。
答案 5 :(得分:19)
List<T> targetCollection = new ArrayList<T>();
CollectionUtils.addAll(targetCollection, iterable.iterator())
以下是此实用程序方法的完整来源:
public static <T> void addAll(Collection<T> collection, Iterator<T> iterator) {
while (iterator.hasNext()) {
collection.add(iterator.next());
}
}
答案 6 :(得分:14)
在此期间,不要忘记所有收藏都是有限的,而Iterable没有任何承诺。如果某些东西是可以迭代的,你可以得到一个迭代器,就是这样。
for (piece : sthIterable){
..........
}
将扩展为:
Iterator it = sthIterable.iterator();
while (it.hasNext()){
piece = it.next();
..........
}
it.hasNext()不需要返回false。因此,在一般情况下,您不能指望能够将每个Iterable转换为Collection。例如,你可以遍历所有正数自然数,迭代一些带有循环的东西,一遍又一遍地产生相同的结果等等。
否则:Atrey的回答非常好。
答案 7 :(得分:14)
我经常使用FluentIterable.from(myIterable).toList()
。
答案 8 :(得分:11)
当您从 Spring Data 获取 Iterable
时,您有几个额外的选择。
您可以使用返回 Iterable
、List
或 Streamable
的版本覆盖存储库中返回 Set
的方法。这样,Spring Data 就会为您进行转换。
您可以在存储库的超级界面中执行此操作,因此您不必在所有存储库界面中重复覆盖。
如果您碰巧使用 Spring Data JPA,这已经在 JpaRepository
您可以自己使用刚才提到的 Streamable
进行转换:
Iterable<X> iterable = repo.findAll();
List<X> list = Streamable.of(iterable).toList();
既然您提到感到沮丧,也许还有一点背景可以帮助您决定使用 Iterable
帮助。
Collection
的情况实际上相当罕见,因此在许多情况下应该不会产生任何影响。Collection
)是不可能的。
这将导致无法返回 Streamable
,该 Streamable
用于商店可能决定在获取所有元素之前返回结果的情况。List
实际上是一种灵活的返回类型,因为它提供了到 Set
、Stream
、Iterable
的简单转换,并且本身就是一个 import numpy as np
list1 = [1, 2, 3, 4]
list2 = [20, 30, 40, 50, 60, 70, 80, 90]
array1 = np.array(list1)
array2 = np.array(list2)
columns = len(list1)
rows = len(list2)
matrix = np.zeros((rows, columns))
for column in range(0, columns):
for row in range(2*column, rows):
matrix[row, column] = round(10 * (array2[row] - array1[column]), 0)
print(matrix)
。但这需要您在应用程序中使用许多用户不喜欢的 Spring Data 特定类型。答案 9 :(得分:10)
在尝试获取List
个Project
而不是在Iterable<T> findAll()
接口中声明的默认CrudRepository
时遇到了类似的情况。因此,在我的ProjectRepository
接口(从CrudRepository
扩展的接口)中,我只声明了findAll()
方法以返回List<Project>
而不是Iterable<Project>
。
package com.example.projectmanagement.dao;
import com.example.projectmanagement.entities.Project;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
public interface ProjectRepository extends CrudRepository<Project, Long> {
@Override
List<Project> findAll();
}
我认为,这是最简单的解决方案,不需要转换逻辑或使用外部库。
答案 10 :(得分:8)
这不是您问题的答案,但我相信这是您问题的解决方案。接口org.springframework.data.repository.CrudRepository
确实具有返回java.lang.Iterable
的方法,但您不应使用此接口。而是使用子接口,在您的情况下org.springframework.data.mongodb.repository.MongoRepository
。此接口具有返回类型为java.util.List
的对象的方法。
答案 11 :(得分:6)
我使用自定义实用程序来投射现有的Collection(如果可用)。
主要强>
public static <T> Collection<T> toCollection(Iterable<T> iterable) {
if (iterable instanceof Collection) {
return (Collection<T>) iterable;
} else {
return Lists.newArrayList(iterable);
}
}
理想情况下,上面会使用ImmutableList,但是ImmutableCollection不允许使用可能会产生不良结果的空值。
<强>试验:强>
@Test
public void testToCollectionAlreadyCollection() {
ArrayList<String> list = Lists.newArrayList(FIRST, MIDDLE, LAST);
assertSame("no need to change, just cast", list, toCollection(list));
}
@Test
public void testIterableToCollection() {
final ArrayList<String> expected = Lists.newArrayList(FIRST, null, MIDDLE, LAST);
Collection<String> collection = toCollection(new Iterable<String>() {
@Override
public Iterator<String> iterator() {
return expected.iterator();
}
});
assertNotSame("a new list must have been created", expected, collection);
assertTrue(expected + " != " + collection, CollectionUtils.isEqualCollection(expected, collection));
}
我为集合的所有子类型(Set,List等)实现了类似的实用程序。我认为这些已经成为番石榴的一部分,但我还没有找到它。
答案 12 :(得分:5)
在Java 8中,您可以执行此操作,将Iterable
中的所有元素添加到Collection
并将其返回:
public static <T> Collection<T> iterableToCollection(Iterable<T> iterable) {
Collection<T> collection = new ArrayList<>();
iterable.forEach(collection::add);
return collection;
}
受到@Afreys回答的启发。
答案 13 :(得分:5)
只要您致电contains
,containsAll
,equals
,hashCode
,remove
,retainAll
,size
或toArray
,无论如何,你必须遍历这些元素。
如果您偶尔只调用isEmpty
或clear
等方法,我认为您最好通过懒惰创建集合。例如,您可以使用后备ArrayList
来存储以前迭代的元素。
我不知道任何图书馆里有这样的课程,但写起来应该是一个相当简单的练习。
答案 14 :(得分:4)
由于RxJava是一把锤子,这看起来像钉子,你可以做到
Observable.from(iterable).toList().toBlocking().single();
答案 15 :(得分:3)
这是一个SSCCE,可以在Java 8中实现这一目标
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class IterableToCollection {
public interface CollectionFactory <T, U extends Collection<T>> {
U createCollection();
}
public static <T, U extends Collection<T>> U collect(Iterable<T> iterable, CollectionFactory<T, U> factory) {
U collection = factory.createCollection();
iterable.forEach(collection::add);
return collection;
}
public static void main(String[] args) {
Iterable<Integer> iterable = IntStream.range(0, 5).boxed().collect(Collectors.toList());
ArrayList<Integer> arrayList = collect(iterable, ArrayList::new);
HashSet<Integer> hashSet = collect(iterable, HashSet::new);
LinkedList<Integer> linkedList = collect(iterable, LinkedList::new);
}
}
答案 16 :(得分:2)
两个评论
答案 17 :(得分:1)
从Cactoos尝试StickyList
:
List<String> list = new StickyList<>(iterable);
答案 18 :(得分:1)
我没有看到没有任何依赖性的简单的一线解决方案。 我简单地使用
List<Users> list;
Iterable<IterableUsers> users = getUsers();
// one line solution
list = StreamSupport.stream(users.spliterator(), true).collect(Collectors.toList());
答案 19 :(得分:0)
您可以使用Eclipse Collections工厂:
Iterable<String> iterable = Arrays.asList("1", "2", "3");
MutableList<String> list = Lists.mutable.withAll(iterable);
MutableSet<String> set = Sets.mutable.withAll(iterable);
MutableSortedSet<String> sortedSet = SortedSets.mutable.withAll(iterable);
MutableBag<String> bag = Bags.mutable.withAll(iterable);
MutableSortedBag<String> sortedBag = SortedBags.mutable.withAll(iterable);
您还可以将Iterable
转换为LazyIterable
并使用转换器方法或任何其他可用的API。
Iterable<String> iterable = Arrays.asList("1", "2", "3");
LazyIterable<String> lazy = LazyIterate.adapt(iterable);
MutableList<String> list = lazy.toList();
MutableSet<String> set = lazy.toSet();
MutableSortedSet<String> sortedSet = lazy.toSortedSet();
MutableBag<String> bag = lazy.toBag();
MutableSortedBag<String> sortedBag = lazy.toSortedBag();
以上所有Mutable
类型都扩展了java.util.Collection
。
注意:我是Eclipse Collections的提交者。
答案 20 :(得分:0)
参加聚会有点晚,但我创建了一个非常优雅的 Java 8 解决方案,它允许将 T 的可迭代对象转换为 T 的任何集合,而无需任何库:
public static <T, C extends Collection<T>> C toCollection(Iterable<T> iterable, Supplier<C> baseSupplier)
{
C collection = baseSupplier.get();
iterable.forEach(collection::add);
return collection;
}
用法示例:
Iterable<String> iterable = ...;
List<String> list = toCollection(iterable, ArrayList::new);