我有以下代码
TreeMap<Integer, List<String>> myMap = new TreeMap<>();
List<Integer> myList = getDataForTest(true);
List<String> wordList = getWordList(true);
List<Integer> intList = Collections.emptyList();
intList = myObj.stream().filter(e->e.getType.equalsIgnoreCase("TEST")).map(e->e.getIntPos()).collect(Collectors.toList())
AtomicInteger pos = new AtomicInteger(0);
myList.stream()
.forEach((entry) ->{
if(CollectionUtils.isEmpty(intList) || intList.contains(pos.get()))
{
myMap.computeIfAbsent(myList.get(pos.get()),k-> new ArrayList<>()).add(wordList.get(pos.get()));
}
pos.incrementAndGet();
});
return myMap;
上面的代码显然会引发编译错误,因为我使用的是 intList ,它在lambda中不是最终的。有没有办法将此lambda替换为流。
答案 0 :(得分:1)
如this answer中所述,空列表的初始分配已过时,并且当您删除它时,只剩下一个分配,这允许从lambda表达式中引用它。但是,当您要做的只是检查集合是否为空或在其上调用DECLARE @T TABLE
(
[Col1] VARCHAR(20)
, [RowNum] INT
) ;
INSERT INTO @T
VALUES
( N'second', 1 )
, ( N'fifth', 4 )
, ( N'fourth', 3 )
--, ( N'zzz', 1 )
, ( N'third', 2 )
---- OR when "zzz" is part of this list
--VALUES
-- ( N'second', 2 )
-- , ( N'fifth', 5 )
-- , ( N'fourth', 4 )
-- , ( N'zzz', 1 )
-- , ( N'third', 3 )
SELECT STUFF ((
SELECT ',' + [SQ].[Col1]
FROM
(
SELECT N'zzz' AS [Col1]
, 0 AS [RowNum]
UNION
SELECT [Col1]
, [RowNum]
FROM @T
) AS [SQ]
ORDER BY [RowNum]
FOR XML PATH ( '' ), TYPE
).[value] ( '.', 'varchar(MAX)' ), 1, 1, ''
) ;
时,最好使用contains
,以便更快地进行查找:
Set
但是有另一种选择。代替通过测试集合中所有列表索引的存在来过滤所有列表索引,我们可以首先迭代集合的索引。我们只需要对它们进行排序和区分即可,使其与通过过滤器的List<Integer> myList = getDataForTest(true);
List<String> wordList = getWordList(true);
Set<Integer> intSet = myObj.stream()
.filter(e -> e.getType().equalsIgnoreCase("TEST")).map(e -> e.getIntPos())
.collect(Collectors.toSet());
IntStream indices = IntStream.range(0, myList.size());
if(!intSet.isEmpty()) indices = indices.filter(intSet::contains);
return indices.boxed().collect(Collectors.groupingBy(myList::get,
TreeMap::new, Collectors.mapping(wordList::get, Collectors.toList())));
索引相同。对于此类操作,更适合使用原始range
值的数组:
int
如果没有将“无索引”视为“无过滤”的特殊处理,我们甚至可以在单个流操作中做到这一点。
答案 1 :(得分:0)
假设这是您的实际代码,为什么不只是将其定型呢?替换
List<Integer> intList = Collections.emptyList();
intList = myObj.stream().filter(e->e.getType.equalsIgnoreCase("TEST")).map(e->e.getIntPos()).collect(Collectors.toList())
与
final List<Integer> intList = myObj.stream().filter(e -> e.getType.equalsIgnoreCase("TEST")).map(e -> e.getIntPos()).collect(Collectors.toList())
除此之外,我认为不可能用流替换您的forEach,因为您在迭代列表时实际上并没有使用列表的entry
做任何事情。实际上,我不太确定您实际上要完成什么。但是为什么不用简单的for循环替换它呢?
for (Integer myVal : myList){
if (CollectionUtils.isEmpty(intList) || intList.contains(pos.get())){
myMap.computeIfAbsent(myList.get(pos.get()), k -> new ArrayList<>()).add(wordList.get(pos.get()));
}
pos.incrementAndGet();
}
答案 2 :(得分:0)
我看了一段时间,然后根据自己的清单提出了一个解决方案 测试数据。
给出以下内容:
List<Integer> myList = List.of(1, 2, 3, 4, 2);
List<String> wordList = List.of("A", "B", "C", "D", "E");
List<Integer> intList = List.of(1, 4, 2);
此流解决方案
AtomicInteger pos = new AtomicInteger(-1);
System.out.println(myMap);
Map<Integer, List<String>> myMap2 = myList.stream().filter(
d ->!intList.isEmpty() &&
intList.contains(pos.incrementAndGet())).collect(
Collectors.groupingBy(d -> d,
TreeMap::new,
Collectors.mapping(d -> wordList.get(pos.get()),
Collectors.toList())));
System.out.println(myMap2);
您的解决方案产生
{2 = [B,E],3 = [C]}
我确定可以对其进行调整以提供所需的内容。
但是,在forEach
上使用常规myList
循环并没有错。由于没有atomic integer
限制,它还使您可以摆脱effective final
。
int i = 0;
for (int entry : myList) {
if (!intList.isEmpty() && intList.contains(i)) {
System.out.println("entry = " + entry);
myMap.computeIfAbsent(myList.get(i), k -> new ArrayList<>()).add(
wordList.get(i));
}
i++;
}