2

What is the most efficient method to find specific hash within array and replace its values in-place, so array get changed as well?

I've got this code so far, but in a real-world application with loads of data, this becomes the slowest part of application, which probably leaks memory, as unbounded memory grows constantly when I perform this operation on each websocket message.

array = 
  [ 
    { id: 1,
      parameters: {
        omg: "lol"
     },
     options: {
         lol: "omg"
      }
    },
    { id: 2,
      parameters: {
        omg: "double lol"
      },
      options: {
        lol: "double omg"
      }
    }
  ]

selection = array.select { |a| a[:id] == 1 }[0]
selection[:parameters][:omg] = "triple omg"
p array
# => [{:id=>1, :parameters=>{:omg=>"triple omg"}, :options=>{:lol=>"omg"}}, {:id=>2, :parameters=>{:omg=>"double lol"}, :options=>{:lol=>"double omg"}}]
1
  • 1
    Also, select { .. }[0] => detect { .. }...detect will stop once it finds the first value that matches, select returns all matching elements in the array and so has to look at every element regardless of if the match is the first element, and then you discard everything but the first Commented Jul 11, 2018 at 16:35

1 Answer 1

3

This will do what you're after looping through the records only once:

array.each { |hash| hash[:parameters][:omg] = "triple omg" if hash[:id] == 1 }

You could always expand the block to handle other conditions:

array.each do |hash| 
  hash[:parameters][:omg] = "triple omg" if hash[:id] == 1
  hash[:parameters][:omg] = "quadruple omg" if hash[:id] == 2
  # etc
end

And it'll remain iterating over the elements just the once.

It might also be you'd be better suited adjusting your data into a single hash. Generally speaking, searching a hash will be faster than using an array, particularly if you've got unique identifier as here. Something like:

{ 
  1 => {
    parameters: {
      omg: "lol"
    },
    options: {
      lol: "omg"
    }
  },
  2 => {
    parameters: {
      omg: "double lol"
    },
    options: {
      lol: "double omg"
    }
  } 
}

This way, you could just call the following to achieve what you're after:

hash[1][:parameters][:omg] = "triple omg"

Hope that helps - let me know how you get on with it or if you have any questions.

Sign up to request clarification or add additional context in comments.

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.