0

I have an array of floating numbers and a certain cutoff:

myData = [1.3,1.5,1.7,1.7,16.7,18.4,19.2,19.5,19.6,20.2,20.8,58.4,60.7,
          61.2,61.2,116.4,121.2,122.7,123.2,123.2,138.5,149.5,149.5]
myBin = 5.3

I'd like to build a hash of arrays so that the difference by subtraction between the last element and the first element of the array is less or equal to myBin (5.3)

myHash = {
'hap_1' => [1.3,1.5,1.7],
'hap_2' => [16.8, 18.4,19.2,19.5,19.6,20.2,20.8],
'hap_3' => [58.4,60.7,61.2,61.2],
'hap_4' => [116.4,121.2],
'hap_5' => [122.7,123.2,123.2],
'hap_6' => [138.5],
'hap_7' => [149.5,149.5]}

Thank you so much in advance for your time and helpful assistance. Cheers

2
  • 1
    Have you attempted a solution yourself? Commented Oct 26, 2017 at 18:03
  • 1
    You should use snake_case for variable names in Ruby. Commented Oct 26, 2017 at 18:29

3 Answers 3

6

Enumerable#slice_before can solve your problem:

first = myData[0]
myData.slice_before { |e| first = e if e - first > myBin }.to_a
#=> [[1.3, 1.5, 1.7, 1.7],
#    [16.7, 18.4, 19.2, 19.5, 19.6, 20.2, 20.8],
#    [58.4, 60.7, 61.2, 61.2],
#    [116.4, 121.2],
#    [122.7, 123.2, 123.2],
#    [138.5],
#    [149.5, 149.5]]
Sign up to request clarification or add additional context in comments.

2 Comments

Solves the core issue however note the OP wanted a hash. Unless you left it on purpose to leave the OP something to do:)
Lovely answer. As you are relying on nil being returned when the if clause is not true, it may be more clear to write myData.slice_before { |n| n-first > myBin ? (first=n) : false }.to_a. Two variants are myData.slice_when { |_,n| n-first > myBin ? (first=n) : false }.to_a and myData.chunk_while { |_,n| n-first <= myBin ? true : !(first=n) }.to_a.
1
myData.drop(1).each_with_object([[myData.first]]) { |n,a|
  n - a.last.first <= myBin ? (a.last << n) : a << [n] }.
  each.with_index(1).with_object({}) { |(a,i),h| h["hap_#{i}"] = a }
  #=> {"hap_1"=>[1.3, 1.5, 1.7, 1.7],
  #    "hap_2"=>[16.7, 18.4, 19.2, 19.5, 19.6, 20.2, 20.8],
  #    "hap_3"=>[58.4, 60.7, 61.2, 61.2],
  #    "hap_4"=>[116.4, 121.2],
  #    "hap_5"=>[122.7, 123.2, 123.2],
  #    "hap_6"=>[138.5],
  #    "hap_7"=>[149.5, 149.5]}

Comments

0

You could build a customer enumerator that works like chunk_while, but compares each chunk's first element to the current one, i.e. 1.3 to 1.5, then 1.3 to 1.7 and so on:

module Enumerable
  def chunk_while1
    return enum_for(__method__) unless block_given?
    each_with_object([]) do |elt, result|
      if result.last && yield(result.last.first, elt)
        result.last << elt
      else
        result << [elt]
      end
    end
  end
end

Usage:

data = [
  1.3, 1.5, 1.7, 1.7, 16.7, 18.4, 19.2, 19.5, 19.6, 20.2, 20.8, 58.4, 60.7,
  61.2, 61.2, 116.4, 121.2, 122.7, 123.2, 123.2, 138.5, 149.5, 149.5
]

result = data.chunk_while1 { |i, j| j - i <= 5.3 }
#=> [
#     [1.3, 1.5, 1.7, 1.7],
#     [16.7, 18.4, 19.2, 19.5, 19.6, 20.2, 20.8],
#     [58.4, 60.7, 61.2, 61.2],
#     [116.4, 121.2],
#     [122.7, 123.2, 123.2],
#     [138.5],
#     [149.5, 149.5]
#   ]

The result can then be converted to a hash, e.g. via:

result.map.with_index(1) { |a, i| ["hap_#{i}", a] }.to_h
#=> {
#     "hap_1"=>[1.3, 1.5, 1.7, 1.7],
#     "hap_2"=>[16.7, 18.4, 19.2, 19.5, 19.6, 20.2, 20.8],
#     "hap_3"=>[58.4, 60.7, 61.2, 61.2],
#     "hap_4"=>[116.4, 121.2],
#     "hap_5"=>[122.7, 123.2, 123.2],
#     "hap_6"=>[138.5],
#     "hap_7"=>[149.5, 149.5]
#   }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.