如何从排序的 Ruby 数组中删除所有元素,这些元素与其最近的邻居比限制更近?
How to remove all elements from sorted Ruby array which are closer to its closest neighbour than a limit?
我的 Ruby 程序中有一个排序的实数数组。我想删除所有非常 "similar" 的元素:它们的差异小于给定的限制。所以最后我只想保留那些与其他元素很好区分的元素,不同的元素:原始数组中没有其他元素比限制更接近它们。
目前我正在试验这两种方法:
limit=0.5
vvs=vv.sort.reverse.each_cons(2).map{|a,b| (a-b).abs<limit ? nil : a}.compact
和
vvs=vv.each_cons(3).map{|a,b,c| (a-b).abs<limit && (b-c).abs<limit ? nil : b}.compact
我的程序需要使用这种方法来同步字幕,并且这些值可能包含一些噪音。由于这个事实,我只想分析那些即使存在一些附加噪声也可以区分的不同元素。
我的原始真实数据来自"Catch 22"https://pastebin.com/mRiS02mb
没有检查真实数据,但可能类似于(从 0
开始,但可以更改为 -Float::INFINITY
):
data = [1, 1.05, 1.5, 1.5, 1.9, 2, 2.1, 3, 3.6, 4, 4.1]
delta = 0.5
data.each_with_object([]) { |e, o| o << e if e >= (o.last || 0) + delta }
#=> [1, 1.5, 2, 3, 3.6, 4.1]
鉴于此示例数据:
data = [
1.07, 1.14, 1.14, 1.24, 1.55, 1.56, 1.82, 1.83, 2.04, 2.16, 2.23,
2.37, 2.38, 2.39, 2.41, 2.46, 2.54, 2.58, 2.93, 2.94, 2.98, 3.06,
3.12, 3.18, 3.62, 3.65, 3.69, 3.87, 4.0, 4.25, 4.36, 4.36, 4.38,
4.63, 4.78, 4.8, 4.83, 4.86, 5.13, 5.37
]
您可以按四舍五入的值对数字进行分组:
limit = 0.5
grouped_data = data.group_by { |f| (f / limit).round * limit }
#=> {
# 1.0 => [1.07, 1.14, 1.14, 1.24],
# 1.5 => [1.55, 1.56],
# 2.0 => [1.82, 1.83, 2.04, 2.16, 2.23],
# 2.5 => [2.37, 2.38, 2.39, 2.41, 2.46, 2.54, 2.58],
# 3.0 => [2.93, 2.94, 2.98, 3.06, 3.12, 3.18],
# 3.5 => [3.62, 3.65, 3.69],
# 4.0 => [3.87, 4.0],
# 4.5 => [4.25, 4.36, 4.36, 4.38, 4.63],
# 5.0 => [4.78, 4.8, 4.83, 4.86, 5.13],
# 5.5 => [5.37]
# }
0.75 到 1.25 的值在 1.0
槽中,1.25 到 1.75 的值在 1.5
槽中,依此类推。
现在从组中选择一个值,例如第一个:
grouped_data.map { |k, vs| vs.first }
#=> [1.07, 1.55, 1.82, 2.37, 2.93, 3.62, 3.87, 4.25, 4.78, 5.37]
或者中间那个:
grouped_data.map { |k, vs| vs[vs.size/2] }
#=> [1.14, 1.56, 2.04, 2.41, 3.06, 3.65, 4.0, 4.36, 4.83, 5.37]
或最接近其各自插槽值的值:
grouped_data.map { |k, vs| vs.min_by { |v| (k - v).abs } }
#=> [1.07, 1.55, 2.04, 2.46, 2.98, 3.62, 4.0, 4.38, 5.13, 5.37]
请注意,如果相邻插槽的值恰好靠近边界,则它们仍可能在限制内,例如
[1.24, 1.26].group_by { |f| (f / limit).round * limit }
#=> { 1.0 => [1.24], 1.5 => [1.26] }
问题好像有点歧义。我按照我在对该问题的评论中所述进行解释。
data = [ 3.42, 5.49, 6.12, 6.48, 7.11, 8.79, 9.36,
9.54, 10.86, 10.95, 11.07, 13.08, 14.41, 14.92]
limit = 0.5
([-Float::INFINITY].concat(data) << Float::INFINITY).each_cons(3).
select { |a,b,c| b-a >= 0.5 && c-b >= 0.5 }.
map { |_,b,_| b }
#=> [3.42, 5.49, 7.11, 8.79, 14.41, 14.92]
我的 Ruby 程序中有一个排序的实数数组。我想删除所有非常 "similar" 的元素:它们的差异小于给定的限制。所以最后我只想保留那些与其他元素很好区分的元素,不同的元素:原始数组中没有其他元素比限制更接近它们。
目前我正在试验这两种方法:
limit=0.5
vvs=vv.sort.reverse.each_cons(2).map{|a,b| (a-b).abs<limit ? nil : a}.compact
和
vvs=vv.each_cons(3).map{|a,b,c| (a-b).abs<limit && (b-c).abs<limit ? nil : b}.compact
我的程序需要使用这种方法来同步字幕,并且这些值可能包含一些噪音。由于这个事实,我只想分析那些即使存在一些附加噪声也可以区分的不同元素。
我的原始真实数据来自"Catch 22"https://pastebin.com/mRiS02mb
没有检查真实数据,但可能类似于(从 0
开始,但可以更改为 -Float::INFINITY
):
data = [1, 1.05, 1.5, 1.5, 1.9, 2, 2.1, 3, 3.6, 4, 4.1]
delta = 0.5
data.each_with_object([]) { |e, o| o << e if e >= (o.last || 0) + delta }
#=> [1, 1.5, 2, 3, 3.6, 4.1]
鉴于此示例数据:
data = [
1.07, 1.14, 1.14, 1.24, 1.55, 1.56, 1.82, 1.83, 2.04, 2.16, 2.23,
2.37, 2.38, 2.39, 2.41, 2.46, 2.54, 2.58, 2.93, 2.94, 2.98, 3.06,
3.12, 3.18, 3.62, 3.65, 3.69, 3.87, 4.0, 4.25, 4.36, 4.36, 4.38,
4.63, 4.78, 4.8, 4.83, 4.86, 5.13, 5.37
]
您可以按四舍五入的值对数字进行分组:
limit = 0.5
grouped_data = data.group_by { |f| (f / limit).round * limit }
#=> {
# 1.0 => [1.07, 1.14, 1.14, 1.24],
# 1.5 => [1.55, 1.56],
# 2.0 => [1.82, 1.83, 2.04, 2.16, 2.23],
# 2.5 => [2.37, 2.38, 2.39, 2.41, 2.46, 2.54, 2.58],
# 3.0 => [2.93, 2.94, 2.98, 3.06, 3.12, 3.18],
# 3.5 => [3.62, 3.65, 3.69],
# 4.0 => [3.87, 4.0],
# 4.5 => [4.25, 4.36, 4.36, 4.38, 4.63],
# 5.0 => [4.78, 4.8, 4.83, 4.86, 5.13],
# 5.5 => [5.37]
# }
0.75 到 1.25 的值在 1.0
槽中,1.25 到 1.75 的值在 1.5
槽中,依此类推。
现在从组中选择一个值,例如第一个:
grouped_data.map { |k, vs| vs.first }
#=> [1.07, 1.55, 1.82, 2.37, 2.93, 3.62, 3.87, 4.25, 4.78, 5.37]
或者中间那个:
grouped_data.map { |k, vs| vs[vs.size/2] }
#=> [1.14, 1.56, 2.04, 2.41, 3.06, 3.65, 4.0, 4.36, 4.83, 5.37]
或最接近其各自插槽值的值:
grouped_data.map { |k, vs| vs.min_by { |v| (k - v).abs } }
#=> [1.07, 1.55, 2.04, 2.46, 2.98, 3.62, 4.0, 4.38, 5.13, 5.37]
请注意,如果相邻插槽的值恰好靠近边界,则它们仍可能在限制内,例如
[1.24, 1.26].group_by { |f| (f / limit).round * limit }
#=> { 1.0 => [1.24], 1.5 => [1.26] }
问题好像有点歧义。我按照我在对该问题的评论中所述进行解释。
data = [ 3.42, 5.49, 6.12, 6.48, 7.11, 8.79, 9.36,
9.54, 10.86, 10.95, 11.07, 13.08, 14.41, 14.92]
limit = 0.5
([-Float::INFINITY].concat(data) << Float::INFINITY).each_cons(3).
select { |a,b,c| b-a >= 0.5 && c-b >= 0.5 }.
map { |_,b,_| b }
#=> [3.42, 5.49, 7.11, 8.79, 14.41, 14.92]