java - 如何按需遍历列表列表?
问题描述
如标题所示,我正在寻找有关如何实现getNextCombination
下面代码片段中显示的方法的解决方案。
public class Test {
private final List<List<String>> iterators;
/**
* @return null if no combination left
*/
public String[] getNextCombination() {
return null;
}
}
假设属性iterator
看起来像
[0]={1,2}
[1]={4,5}
[2]={7,8}
那么对该getNextCombination
方法的顺序调用应该返回类似于以下的内容:
147
148
157
158
247
248
...
NULL
如何尽可能高效地实现这一目标?
谢谢你的帮助。
解决方案
以下用于计算所有组合的通用惰性函数可以完成这项工作并适用于任意数量的列表或任何其他结构
static Stream<int []> combinationsStream(final int... numElems) {
final int numCombinations = Arrays.stream(numElems) // the number of solutions is
.map(n -> n + 1) // possibles sizes
.reduce(1, (a, b) -> a * b); // product
final int[] queue = Arrays.stream(numElems).map(i -> -1).toArray(); // for every item take n elements
final int[] i = new int[]{0}; // volatile (final) integer
final Function<int [], int []> next = o -> { // compute the next combination
while (true) {
if (i[0] == numElems.length) { // if is the last position
i[0] -= 1; // we will back
return queue; // but it's a combination
}
queue[i[0]] += 1; // take one more of i[0]-th element
if (queue[i[0]] > numElems[i[0]]) // if no more of this
queue[i[0]--] = -1; // reset and go back
else
i[0] += 1; // if not, go forward
}
};
return Stream.iterate(null, next::apply) // iterate getting next over and over
.skip(1) // avoid the seed (null)
.limit(numCombinations); // limit the stream to combs number
}
因为只使用索引,你可以使用如下
让你的清单:
// let you list of list (from somewhere)
List<List<String>> iterators = asList(
asList("1", "2"),
asList("4", "5"),
asList("7", "8")
);
(列表可能包含不同数量的元素)
然后,要获得所有组合的惰性流,只需将列表列表转换为最大索引数组
// we get combinations in a lazy way simply with
// (you could set this stream in your private class field if you wish)
Stream<int []> lazyCombinations = combinationsStream(iterators.stream()
.mapToInt(g -> g.size() - 1).toArray());
在您的情况下,调用将是combinationsStream(1, 1, 1)
因为有效索引适用0, 1
于每个列表。
要将某些索引组合转换为您的String
输出,请获取索引并加入
// to convert the indexes array to values (and concatenate all) you can write the function
Function<int [], String> toString = indexes -> IntStream
// for each list
.range(0, indexes.length)
// get the indexes[i]-th element
.mapToObj(i -> iterators.get(i).get(indexes[i]))
// and join
.collect(joining());
然后,只需将前一个映射Stream<int []>
到Stream<String>
使用该函数
// now you can convert your indexes stream to your final combinations stream (all lazy)
Stream<String> lazySolutions = lazyCombinations.map(toString);
您可以通过Stream
多种方式使用(即懒惰地在 Web 服务中返回),但是,如果您希望一一采用,您可以转换为迭代器。
迭代器也很懒
// if you need peek combinations on demand (not in a streaming way) convert stream to iterator
Iterator<String> lazyIterator = lazySolutions.iterator();
然后,你只能拿一个
// you can take one by one (e.g. inside a `getNextCombination`)
System.out.println("Only one: " + lazyIterator.next());
或您考虑的数量
// or to the end
lazyIterator.forEachRemaining(System.out::println);
带输出
Only one: 147
148
157
158
247
248
257
258
推荐阅读
- ios - 增加 AVAudioPCMBuffer 的音量(标准化)
- amazon-web-services - 使 Amazon S3 存储桶中的每个对象均可公开访问
- spring-boot - 字符串参数“变量名”没有定义最大长度
- android - Xamarin.Android:错误 android.view.View.mPrivateFlags NullReferenceException
- git - 当我尝试删除分支时,我收到一条消息说“Head is now at f33dc83”
- reactjs - 如何制作具有泛型类型的功能性 React 组件?
- python - Python,在同一行打印
- editor - 如何使用 vi 编辑器在文件中搜索目录路径
- discord.py - 如何让我的 discord.py 机器人只允许来自管理员和模组的 @everyone 和 @here,而不是来自普通成员的
- java - 如何更改标记位置并使用它更改谷歌地图视图