SketchUp Ruby编程:提取数组中匹配与不匹配的Point3d元素
Ruby数组按Point3d对象匹配筛选解决方案
问题描述
需要处理两个包含Point3d对象的Ruby数组,目标是:
- 从数组
a中筛选出Point3d在数组b中存在的子数组(即result_match) - 从数组
b中筛选出Point3d不在数组a中存在的子数组(即result_non_match)
尝试过samepoint = a.map(&:to_a) & b.map(&:to_a)但未成功。
输入示例
a = [['xxx', [0.203125, 0.203125, 0.0], Point3d(12, 1.25984, -0.275591), nil], ['eee', [0.203125, 0.203125, 0.0], Point3d(12, 20.0995, -0.275591), nil]] b = [['aaa', [0.203125, 0.203125, 0.0], Point3d(10, 1.25984, -0.275591), nil], ['sss', [0.203125, 0.203125, 0.0], Point3d(10, 20.0995, -0.275591), nil], ['www', [0.203125, 0.203125, 0.0], Point3d(12, 1.25984, -0.275591), nil], ['nnn', [0.203125, 0.203125, 0.0], Point3d(12, 20.0995, -0.275591), nil]]
失败原因分析
直接使用map(&:to_a)后取交集的方法失效,通常有两个原因:
- Point3d对象的相等性判断:默认情况下Ruby对象的
==比较内存地址,而非坐标值。即使to_a返回坐标数组,若Point3d未正确实现to_a方法,也无法生成可比较的坐标数组。 - 浮点数精度问题:坐标中的浮点数可能存在微小精度差异,直接比较数组会导致匹配失败。
解决方案
前提假设
假设你使用的Point3d类(比如SketchUp的Point3d)已实现按坐标值判断相等的==方法,或可以通过to_a返回包含x/y/z坐标的数组。
代码实现
1. 筛选匹配的子数组(result_match)
先提取数组b中的所有Point3d对象存入集合(集合查找效率更高),再从a中筛选符合条件的子数组:
require 'set' # 提取b中所有Point3d对象,存入集合 b_points = Set.new(b.map { |sub_arr| sub_arr[2] }) # 从a中筛选Point3d存在于b_points的子数组 result_match = a.select { |sub_arr| b_points.include?(sub_arr[2]) }
2. 筛选不匹配的子数组(result_non_match)
提取数组a中的所有Point3d对象存入集合,再从b中排除符合条件的子数组:
require 'set' # 提取a中所有Point3d对象,存入集合 a_points = Set.new(a.map { |sub_arr| sub_arr[2] }) # 从b中筛选Point3d不存在于a_points的子数组 result_non_match = b.reject { |sub_arr| a_points.include?(sub_arr[2]) }
处理浮点数精度问题
如果存在浮点数精度差异导致匹配失败,可以将坐标值四舍五入后再比较:
require 'set' # 提取b中Point3d的坐标数组(四舍五入到5位小数) b_coords = Set.new(b.map { |sub_arr| sub_arr[2].to_a.map { |num| num.round(5) } }) # 筛选匹配的子数组 result_match = a.select { |sub_arr| coords = sub_arr[2].to_a.map { |num| num.round(5) } b_coords.include?(coords) } # 提取a中Point3d的坐标数组 a_coords = Set.new(a.map { |sub_arr| sub_arr[2].to_a.map { |num| num.round(5) } }) # 筛选不匹配的子数组 result_non_match = b.reject { |sub_arr| coords = sub_arr[2].to_a.map { |num| num.round(5) } a_coords.include?(coords) }
验证结果
运行上述代码后,将得到期望输出:
result_match为数组a的两个子数组(其Point3d在b中存在)result_non_match为数组b的前两个子数组(其Point3d不在a中存在)
内容的提问来源于stack exchange,提问作者JoMojo
相关产品推荐
相关产品推荐

