使用Stream从两个列表创建值分组映射(无匹配值为空列表)
没问题,我来帮你实现这个映射逻辑!先明确核心规则,再给你代码示例和解释:
实现思路与规则明确
首先得把需求里的规则拆解清楚:
- 映射的键是
sampleBins列表的元素索引(比如示例里sampleBins = [0,10,20,30,40,50,60],对应键0到6) - 每个键
n对应的数值区间是[sampleBins[n], sampleBins[n+1))(左闭右开);最后一个键(比如示例里的6)因为没有后续的bin值,所以没有对应区间,直接对应空列表 - 遍历
samples中的每个数值,找到它所属的区间,将其添加到对应键的列表中;所有键必须出现在映射里,没有匹配数值的键对应空列表
Java代码实现(基础版本)
这里用Java实现,和你给出的示例场景匹配,用LinkedHashMap保证键的顺序和索引一致:
import java.util.*; public class BinValueMapper { public static void main(String[] args) { // 示例输入 List<Integer> sampleBins = Arrays.asList(0, 10, 20, 30, 40, 50, 60); List<Integer> samples = Arrays.asList(5, 6, 55, 52); // 初始化映射:每个索引键对应空列表 Map<Integer, List<Integer>> binToValues = new LinkedHashMap<>(); for (int i = 0; i < sampleBins.size(); i++) { binToValues.put(i, new ArrayList<>()); } // 遍历每个样本值,分配到对应区间 for (int num : samples) { int targetKey = -1; // 遍历区间找匹配 for (int i = 0; i < sampleBins.size() - 1; i++) { int lowerBound = sampleBins.get(i); int upperBound = sampleBins.get(i + 1); if (num >= lowerBound && num < upperBound) { targetKey = i; break; } } // 如果找到对应键,添加数值 if (targetKey != -1) { binToValues.get(targetKey).add(num); } } // 打印结果验证 binToValues.forEach((key, values) -> System.out.printf("键%d: %s%n", key, values)); } }
运行这段代码后,输出和你期望的完全一致:
键0: [5, 6] 键1: [] 键2: [] 键3: [] 键4: [] 键5: [55, 52] 键6: []
优化版本(大数据量场景)
如果sampleBins的长度很大,基础版本的线性查找效率会很低,这里可以用二分查找优化区间匹配逻辑,把时间复杂度从O(n)降到O(logn):
// 替换基础版本中的样本值遍历部分 for (int num : samples) { // 用二分查找定位数值位置 int searchResult = Collections.binarySearch(sampleBins, num); int targetKey; if (searchResult >= 0) { // 数值正好等于某个bin值,属于当前索引的区间 targetKey = searchResult; } else { // 二分查找返回-(插入点)-1,插入点是第一个大于num的元素索引 int insertionPoint = -(searchResult + 1); targetKey = insertionPoint - 1; } // 验证targetKey是否在有效区间范围内(0到sampleBins.size()-2) if (targetKey >= 0 && targetKey < sampleBins.size() - 1) { binToValues.get(targetKey).add(num); } }
这个优化版本在处理大量样本数据时会快很多,结果和基础版本完全一致。
内容的提问来源于stack exchange,提问作者ppysz
相关产品推荐
相关产品推荐

