0

I have a User class as follows:

class User
        attr_reader   :username, :password
        def inintialize(username, password)
                @username    = username
                @password    = password
        end
end

And I want to store many of these User classes in an array as follows:

users = []

def initialize_users
        user = User.new("user0", "password0")
        users.push(user)

        user = User.new("user1", "password1")
        users.push(user)
end

And now I want to implement a searching function where I can search via username, or password. I know I can iterate over the classes comparing each field like so:

def search(username)
        users.each do |user|
                if user.username == username then
                        puts "Found"
                        break
                end
        end
end

But is there any other way to do this without the iterating or is this simply the easiest/cleanest way?

I was thinking maybe there is a way to do something like:

users["username_to_find"]
=> true

Although I am not sure how to implement that. I would believe I would have to rewrite the User class to have a built in list, but from there I am lost. I guess even if I do implement this feature there is still a iteration that has to happen.

Also I would like to access that users data from within that notation such as

users["username_to_find"].password
=> "password111"

Anyone have any ideas?

PS: User class is reduced to relevant code, it actually holds many more data members which are specific to each user such as sockets, and methods for sending data to a specific users sockets.

randy newfield
  • 1,221
  • 3
  • 25
  • 38
  • Welcome to Stack Overflow. When creating a title, please don't arbitrarily tack on "ruby" or similar words you've picked as tags to the beginning or end of the sentence. Use a normal sentence instead. Stack Overflow uses the tags we define when searching, along with supplying them to the search engines. If you can work them into the normal flow of the sentence that's cool, but don't artificially add them. – the Tin Man May 18 '15 at 21:07

3 Answers3

0

If it doesn't need to be an Array, why not use a Hash? It provides exactly the functionality you want.

users = {}
user = User.new("user0", "password0")
users[user.username] = user

Access it like so

users['tim_the_toolman'] # => nil, there is no user by that name
users['user0'] # => returns user0
users['user0'].password # => 'password0'
dax
  • 10,779
  • 8
  • 51
  • 86
  • How fast is a hash lookup compared to iterating an array via the methods djaszczurowski mentioned? I could possibly rework my project to use hashes easily enough rather than having the methods built into the `User` class. – randy newfield May 18 '15 at 21:15
0

You really have no choice but to iterate over every element of the array and perform your matching test. Enumberable#detect is what you would want to use:

def search(username)
  # return the first matching result
  users.detect { |user| user.username == username }
end

This would return the first User with a matching username or nil. If you want to allow multiple results to be returned (e.g. more of what the word "search" denotes) than you would want to use Enumberable#select which returns all matching blocks:

def search(username)
  # return ALL matching results
  users.select { |user| user.username == username }
end

If you need to potentially match on multiple criteria (e.g. search on username and first name, etc) than you will need to take this approach. If you are only searching on username, than the solution given by @dax above is perfect.

Cody Caughlan
  • 32,456
  • 5
  • 63
  • 68
0

use Array find and select methods. Assume you are searching by name

  1. find returns first object which satisfies your condition

array.find { |user| user.name == searched_name } # will be either one User or nil, if neither has name eq to searched_name

  1. select returns all objects which satisfy your condition

array.select { |user| user.name == searched_name } #will be either array of Users which have name eq searched_name or an empty array when none has this name

djaszczurowski
  • 4,385
  • 1
  • 18
  • 28
  • Does this still iterate through the array? If presumably I have a large database of users, how long would this take vs say searching a hash via hash['username'] notation? – randy newfield May 18 '15 at 21:13
  • `hash['username']` will be faster. If you have Users in db maybe you should make proper db query by name, so that only these Users were returned? If you want use hash, remember that first you must map array of Users to hash structure. It's easy but will take some time as well. In your case that would be: `array.inject({}) { |memo, user| memo[user.username] = user; memo }` – djaszczurowski May 18 '15 at 21:18