2

I have multiple arrays which have code string items in them. I need to match the code from a given string and then return a class name from the matched array.

Might be better if I show you what I've got. So below are the arrays and underneath this is the string I need to return if the given string matches an item from within the array. So lets say I send a string of '329' this should return 'ss4' as a string:

['392', '227', '179', '176']
= 'ss1'

['389', '386']
= 'ss2'

['371', '338', '335']
= 'ss3'

['368', '350', '332', '329', '323', '185', '182']
= 'ss4'

I need to know what would be the best approach for this. I could create a helper method and have an array for each code block and then check each array to see if the given string code is contained and then return the string, which could be ss1 or ss4. Is this a good idea?

2
  • 1
    What is code string item? They do not look like strings. And, class name differs for each array? What are the classes? Commented Apr 25, 2013 at 14:15
  • sorry I was being lazy as I didn't add quotes around the codes. Commented Apr 25, 2013 at 14:18

5 Answers 5

5

The most efficient approach would be to generate a translator hash once that can perform the lookup super fast:

CODES = {
  ss1: ['392', '227', '179', '176'],
  ss2: ['389', '386'],
  ss3: ['371', '338', '335'],
  ss4: ['368', '350', '332', '329', '323', '185', '182']
}

translator = CODES.each_with_object({}){|(s, a), m| a.each{|n| m[n] = s.to_s}}

Now you can simply do:

translator['329']
=> "ss4"
translator['389']
=> "ss2"
Sign up to request clarification or add additional context in comments.

4 Comments

+1 This should be very fast and scale well. Might want to use each_with_object instead of inject though, because it tends to be cleaner with this sort of task.
Does the 'each_with_object' method exist when there is a match then? I like the select method that @d_ethier has done as this is much easier to read but as mentioned before this will not exit the loop even if a match is true.
@Peter, each_with_object is called once to build the translator hash. After this one time it is never called again. You then simply check against the hash to get your results.
@PinnyM thank you. I can see what its doing now. Also my above comment should say 'exit' not 'exist' :)
1
def code_to_string(code)
  if [395].include? code
    "ss1"
  elsif [392, 227, 179, 176].include? code
    "ss2"
  # and so on
end

Note that the codes are integers. to match with a string code, use %w(392 227 179).include? instead of the array

4 Comments

This won't scale well at all and even with the limited cases given this method would look pretty nasty with all the branches containing long [...].include? code statements
@Paul.s Most likely this lists are defined elsewhere, maybe even generated dynamically, so of course he could reuse this lists with the proper meaning in my method. But if used only here, I like better having the arrays like this instead in another place because it is easier to see what is happening (one code jump less). While the answer from @PunnyM is faster, it is way less legible. So I can't give the right answer between my and his answers because I don't know what he means by best approach
A best approach is any one that solves the problem in an efficient manner while keeping with best practices. The 'illegible' code simply turns the hash inside out - it's quite legible to me, but I guess that's subjective.
@PinnyM I can read it, and perhaps so do you - the question you have to make yourself is "can my team mate read it?". Anyway, if his answer serves you best, you should pick it - I don't think you can have anything faster than a hash. I'll keep mine here as an alternative
0

Here's one solution you could try:

CODE_LOOKUP = {
  [395] => 'ss1',
  [392, 227, 179, 176] => 'ss2',
  [389, 386] => 'ss3'
  # etc
}

def lookup_code(code)
  CODE_LOOKUP.each do |codes_to_test, result|
    return result if codes_to_test.include?(code)
  end
end

lookup_code(395)
# => "ss1"

lookup_code(179)
# => "ss2"

1 Comment

This would slow down as the list of codes increase, especially if the targeted code is at the bottom of the hash.
0
h = {:ss1 => [395],:ss2 => [392, 227, 179, 176] }
h.key(h.values.find{|x| x.include? "392".to_i})
#=> :ss2

Comments

0

I'd recommend joining all the arrays into a multi-dimensional hash and then searching that.

a1 = ['395']
a2 = ['392', '227', '179', '176']

h = { a1: a1, a2: a2 }
h.select {|a, v| a if v.include?('392') }.keys.first.to_s

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.