I have an array, "templates".
puts templates
gives me the following output:
{"id"=>4, "subject"=>"invoice", "body"=>"dear sirs", "description"=>"banking", "groups"=>"123", 0=>4, 1=>"invoice", 2=>"dear sirs", 3=>"banking", 4=>"123"}
I would like to "put" a certain element e.g. "dear sirs". I have tried:
puts templates[2]
but this just returns nil. What is the correct way to do this?
You access "dear sirs" using the key that's associated with it, "body":
puts templates["body"]
Suppose if you have hash like this
#a = {"id"=>4, "subject"=>"invoice", "body"=>"dear sirs", "description"=>"banking", "groups"=>"123", 0=>4, 1=>"invoice", 2=>"dear sirs", 3=>"banking", 4=>"123"}
And if you want to get value of key name 'body', then you can get output like this,
puts #a['body'] //Output = dear sirs
puts #a['subject'] //Output = invoice
For more information for ruby hash Ruby Hash
If you want to get a hash value by numeric index then you can do templates.values[index]
e.g
templates.values[0] => 4
templates.values[1] => "invoice"
templates.values[2] => "dear sirs"
Note: My answer is based on strong assumptions that may not be true. I have provided steps to validate that.
In-case you are on older ruby version you need to do puts templates.inspect in-order to print a Hash. Therefore suggesting your variable templates is a String. Best way to verify:
templates.class
#=> returns Hash or String accordingly.
If it return String, you can proceed as follows:
Convert the String into Hash
hash = eval(templates)
#=> {"subject"=>"invoice", 0=>4, "description"=>"banking", 1=>"invoice", 2=>"dear sirs", "id"=>4, 3=>"banking", "body"=>"dear sirs", 4=>"123", "groups"=>"123"}
Now that its a Hash you can access any value using its key like:
hash[key]
#=> val
Example for your case:
hash[2]
#=> "dear sirs"
Related
How to make a hash that has been pushed into an array independent of the "source" hash?
my %country;
my Hash #array;
%country{ 'country' } = 'France';
#array.push(%country);
%country{ 'country' } = 'Germany';
#array.push(%country);
.say for #array;
The output is:
{country => Germany}
{country => Germany}
And of course it's not what I want.
When you push the hash %country on to the array you are pushing the reference to %country. In this way, each array element will reference the same original hash %country. And when you change a value of the hash all array elements will reflect this change (since they all reference the same hash). If you want to create a new hash each time you push it, you can try push an anonymous hash instead. For example:
%country{ 'country' } = 'France';
#array.push({%country});
%country{ 'country' } = 'Germany';
#array.push({%country});
In this way, a reference to a copy of %country is pushed each time (instead of a reference to %country).
Output:
{country => France}
{country => Germany}
Just about every programming language has this issue. You're pushing the same hash onto the array more than once. When you change the hash, you change both references that are inside the array.
If you push different hashes onto the array, you'll see the result you expect:
my %a = ( country => 'China' );
my %b = ( country => 'USA' );
my Hash #array;
#array.push(%a);
#array.push(%b);
say #array.perl;
You can even copy the hash when you push it onto the array, instead of declaring two hashes. That will also solve this problem:
my %country;
my #array;
%country<country> = 'México';
#array.push(%country.list.hash);
%country<country> = 'Canada';
#array.push(%country.list.hash);
say #array.perl;
By the way, there are a lot of ways to copy a hash. The key is to get the key/values, then turn it back into a hash. Which hash constructor, and which flattening method you use are up to you. (.kv, .list, .pairs, .flat are all Hash methods that will get the elements sequentially, in one way or another. The way Håkon showed is more implicit, getting elements then creating another hash by syntax alone.)
If you just want a simple key value pair (not a multi part hash) consider Pairs?
my Pair #array;
#array.push( (:country<Germany>) );
#array.push( (country => "France") );
say #array;
say .kv for #array
I'm iterating through data and dumping some to a Redis DB. Here's an example:
hmset id:1 username "bsmith1" department "accounting"
How can I increment the unique ID on the fly and then use that during the next hmset command? This seems like an obvious ask but I can't quite find the answer.
Use another key, a String, for storing the last ID. Before calling HMSET, call INCR on that key to obtain the next ID. Wrap the two commands in a MULTI/EXEC block or a Lua script to ensure the atomicity of the transaction.
Like Itamar mentions you can store your index/counter in a separate key. In this example I've chosen the name index for that key.
Python 3
KEY_INDEX = 'index'
r = redis.from_url(host)
def store_user(user):
r.incr(KEY_INDEX, 1) # If key doesn't exist it will get created
index = r.get(KEY_INDEX).decode('utf-8') # Decode from byte to string
int_index = int(index) # Convert from string to int
result = r.set('user::%d' % int_index, user)
...
Note that user::<index> is an arbitrary key chosen by me. You can use whatever you want.
If you have multiple machines writing to the same DB you probably want to use pipelines.
I have a form that displays inputs based on user preferences. I am storing the values as an hstore hash since I dont know ahead of time exactly what the form input for each user will be. The problem I am running in to is that even though a user has an input preferenced doesnt mean they have to enter a value for it each time. Which, can result in :foo => "".
All the doc examples show you how to find records you know the key name of. In my case, I dont know the key name...I need to find all the keys in a hash whose value => "".
Then, I should be able to do something like the docs shows...for each empty value
person.destroy_key(:data, :foo).destroy_key(:data, :bar).save
avals(hstore) is likely what I need to user... How do you use avals with rails?
Since hstore is just a hash in rails...you just need to evaluate the hash before saving it.
...in model
before_save :remove_blanks
private
def remove_blanks
self.hstore = self.hstore.reject{ |k,v| v.blank? }
end
replace 'hstore' with your hstore column name
I am new to rails and I am trying to read a JSON uri. I can read the information but I don´t know how to access the sublevels of the json file. I am doing this:
resp = Net::HTTP.get_response(URI.parse(uri))
parsedresp = JSON.parse(resp.body)
I get as a answer the follow information:
{"success"=>true, "data"=>[{"id"=>1, "public_id"=>1, "company_id"=>60861, "user_id"=>{"value"=>74138, "name"=>"Daniel Galvao"}}]}
When I use parsedresp["data"] I get the information:
[{"id"=>1, "public_id"=>1, "company_id"=>60861, "user_id"=>{"value"=>74138, "name"=>"Daniel Galvao"}}]
My problem is that I don't know how to get the information "name"=>"Daniel Galvao" to store in the DB. Can someone help me? Thanks in advance!
The value of parsedresp["data"] is an array, so to get its value, you have to pass it an index ([0] for the first and only element):
parsedresp["data"][0]
#=> {"id"=>1, "public_id"=>1, "company_id"=>60861, "user_id"=>{"value"=>74138, "name"=>"Daniel Galvao"}}
To get the user data, pass this hash the user_id hash key:
parsedresp["data"][0]["user_id"]
#=> {"value"=>74138, "name"=>"Daniel Galvao"}
If you want to get the name of the user, then:
parsedresp["data"][0]["user_id"]["name"]
#=> "Daniel Galvao"
I'm trying to create a 'search box' that matches users by name.
The difficulty is that a user has both a firstname and a surname. Each of those can have spaces in them (eg "Jon / Bon Jovi", or "Neil Patrick / Harris"), and I'm wondering about the most efficient way to ensure the search is carried out on a concatenation of both the firstname and surname fields.
The list of users is quite large, so performance is a concern. I could just throw a "fullname" def in the user model, but I suspect this isn't the wisest move performance wise. My knowledge of multi-column rails indexes is weak, but I suspect there's a way of doing it via an index with a " " in it?
Just to clarify, I don't need fuzzy matching - exact match only is fine...I just need it to be run on a concatenation of two fields.
Cheers...
You could create a new field in your database called full_name with a regular index, then use a callback to populate this whenever the record is saved/updated:
before_save :populate_full_name
protected
def populate_full_name
self.full_name = "#{first_name} #{last_name}"
end
If you can modify the database, you can and should use the solution provided by gjb.
Here is the solution that does not require you to alter the database. Simply gather all the possible first-name/last-name pairs you can get from the search box. Some code:
# this method returns an array of first/last name pairs given the string
# it returns nil when the string does not look like a proper name
# (i.e. "Foo Bar" or "Foo Bar Baz", but not "Foo" or "Foo "
def name_pairs(string)
return nil unless string =~ /^\w+(\s+\w+)+$/
words = string.split(/\s+/) # split on spaces
result = []
# in the line below: note that there is ... and .. in the ranges
1.upto(words.size-1) {|n| result << [words[0...n], words[n..-1]]}
result.collect {|f| f.collect {|nm| nm.join(" ")}}
end
This method gives you an array of two-element arrays, which you can use to create an or query. Here is how the method looks:
#> name_pairs("Jon Bon Jovi")
=> [["Jon", "Bon Jovi"], ["Jon", "Bon Jovi"]]
#> name_pairs("John Bongiovi")
=> [["John", "Bongiovi"]]
#> name_pairs("jonbonjovi")
=> nil
Of course, this method is not perfect (it does not capitalise the names, but you can do it after splitting) and is probably not optimal in terms of speed, but it works. You can also reopen String and add the method there, so you can go with "Jon Bon Jovi".name_pairs.