iterate an array of strings and perform a regexp - ruby

Given an array of DateTime Strings, I want to just fetch the times e.g. 10:30:00.
So far I come up with this, but it wont give me the right result:
["2011-07-30 10:00:00","2011-07-30 12:00:00"].each{|item| item.match(/\d{2}:\d{2}:\d{2}/)}

If all the strings really are like that then just do some substring mangling:
a = ["2011-07-30 10:00:00","2011-07-30 12:00:00"]
times = a.map { |e| e[11,8] }
This will also work if your timestamps include things like 2011-07-30 10:00:00.1123, 2011-07-30T10:00:00, or 2011-07-30 10:00:00 +0700.
If you wanted to be friendlier to the future, then you could do this:
off = '9999-99-99 '.length
len = '99:99:99'.length
times = a.map { |e| e[off, len] }
so no one would have to guess what the 11 and 8 were all about.

You could achieve the same using the excellent DateTime library from Ruby.
require 'date'
["2011-07-30 10:00:00","2011-07-30 12:00:00"].map{|item|
DateTime.parse(item).strftime("%H:%M:%S")
}
=> ["10:00:00", "12:00:00"]
Though, mu's answer is great.

Related

Finding the sum,highest,lowest in a Hash/Array. Ruby

I am fairly new to this so I apologize in advance of my newbieness. I have been working on a project that I want to get the sum, highest,lowest out of a hash/array. I have tried numerous times to get this right but I typically will get an error such as, fixNum cannot convert int to string and undefined method. I will attempt to fix these issues and then run into another issue so I am at a loss. For the record in my text file I have 1,Foo,22 2,Smith,30 my output looks like this {1=>["Foo",22], 2=>["Smith",30]} I would like the highest number to show 30, lowest to be 22 and total to be 52 for different outputs.
You can do as below suppose lets say a variable a = {a: [a,1],b: [b,1] } then
values = a.values.map(&:last) //Gives the last element of each array
max= a.max
min = a.min
sum = a.sum
Okay, this is very ugly and someone will probably improve upon it but it works. Assuming I understand the output you would like.
elements = h.map{ |element| element[1] }.map { |element| element[1]}
# sum
elements.sum
# highest
elements.max
# lowest
elements.min
https://repl.it/repls/AntiqueOldfashionedRom
Convert to hash and calculate min max based on values
data = "1,Foo,22 2,Smith,30"
people =
data.split(",")
.each_slice(3)
.map {|slice| [slice[0], [slice[1], slice[2]]] }
.to_h
values = people.values.map {|person| person[1] }
min = values.min
max = values.max
sum = values.sum

What's the most efficient way to search words in this kind of file by Ruby

I have a file like:
Fruit.Store={
#blabla
"customer-id:12345,item:store/apple" = 10; #blabla
"customer-id:23456,item:store/banana" = 10; #blabla
"customer-id:23456,item:store/watermelon" = 10;
#blabla
"customer-id:67890,item:store/watermelon" = 10;
}
Except the comments, each line has the same format: customer-id and item:store/ are fixed, and customer-id is a 5-digit number. There are about 1000 unique lines in the file. When "12345" and "apple" are input, the first line should be returned. What's the most efficient way to solve this problem by Ruby? Thank you!
def lookup(input, id, fruit)
IO.foreach(input).detect do |line|
line =~ %r|^\p{Space}*customer-id:#{id},item:store/#{fruit}|
end
end
lookup("/path/to/file", 12345, 'apple')
#⇒ " \"customer-id:12345,item:store/apple\" = 10; #blabla\n"
What's the most efficient way to solve this problem by Ruby?
(Assuming you can load the whole dataset in memory at once and keep it there.)
On load, transform your file into a hash of this shape.
data = {
[12345, 'apple'] => 10,
[23456, 'banana'] => 10,
...
}
Then you just do this:
data[[12345, 'apple']] # => 10 or nil (if not found)
This gives you O(1) lookups. You can't get more efficient than this.
If you want to work on the file directly, then you can read file line-by-line and try detect matching line, as shown in #mudasobwa's answer. The lookups in that case are much less efficient, but, on the other hand, it requires no preprocessing. So if you just want to do one lookup, that might be more efficient overall.

aggregate values from specific key in an array of hashes

I'm trying to build an array of values that come from an array of hashes, at the moment my code looks like this:
ids = array_of_hashes.inject([]) do |result,instance|
result << instance[:id]
result
end
I just want to know if there's a more efficient way to do it?
You could change it to look like:
ids = hash.map { |instance| instance[:id] }
Not necessarily more efficient, but easier to read and maintain!
Good luck!
There are two easy ways for it:
1. ids = hash.collect{|h| h[:id]}
2. ids = hash.map{|h| h[:id]}
Now you would ask what is the difference in both? for explanation see this accepted answer

Ruby: how to find the next match in an array

I have to search an item in an array and return the value of the next item. Example:
a = ['abc.df','-f','test.h']
i = a.find_index{|x| x=~/-f/}
puts a[i+1]
Is there any better way other than working with index?
A classical functional approach uses no indexes (xs.each_cons(2) -> pairwise combinations of xs):
xs = ['abc.df', '-f', 'test.h']
(xs.each_cons(2).detect { |x, y| x =~ /-f/ } || []).last
#=> "test.h"
Using Enumerable#map_detect simplifies it a litte bit more:
xs.each_cons(2).map_detect { |x, y| y if x =~ /-f/ }
#=> "test.h"
The reason something like array.find{something}.next doesn't exist is that it's an array rather than a linked list. Each item is just it's own value; it doesn't have a concept of "the item after me".
#tokland gives a good solution by iterating over the array with each pair of consecutive items, so that when the first item matches, you have your second item handy. There are strong arguments to be made for the functional style, to be sure. Your version is shorter, though, and I'd argue that yours is also more quickly and easily understood at a glance.
If the issue is that you're using it a lot and want something cleaner and more to the point, then of course you could just add it as a singleton method to a:
def a.find_after(&test)
self[find_index(&test).next]
end
Then
a.find_after{|x| x=~/-f/}
is a clear way to find the next item after the first match.
All of that said, I think #BenjaminCox makes the best point about what appears to be your actual goal. If you're parsing command line options, there are libraries that do that well.
I don't know of a cleaner way to do that specific operation. However, it sure looks like you're trying to parse command-line arguments. If so, I'd recommend using the built-in OptionParser module - it'll save a ton of time and hair-pulling trying to parse them yourself.
This article explains how it works.
Your solution working with indexes is fine, as others have commented. You could use Enumerable#drop_while to get an array from your match on and take the second element of that:
a = ['abc.df','-f','test.h']
f_arg = a.drop_while { |e| e !~ /-f/ }[1]

JSON.parse changes sorting - Ruby

In the code below, the order of my items gets changed after the JSON.parse(f) line, i.e., this hash:
{
a => aval,
b => bval,
c => cval,
d => dval
}
becomes something like:
{
b => bval,
c => cval,
a => aval,
d => dval
}
This is a problem because my display code just reads from the json file, so any time I save back to it, and then display, everything gets changed around. Is there anything I can do to retain the order?
CODE:
f = File.read($PLAN_DESC_PATH)
puts ("f " + f.to_s())
hash = JSON.parse(f)
puts ("hash " + hash.to_s())
My Ruby version is 1.8.7. I am using Sinatra. I believe I got the JSON gem from here: http://flori.github.com/json/ (sorry, kinda new to this). Thanks!
In Ruby 1.8.7 the Hash class does not maintain order either by keys or by order added. If you need something like that, you would need to implement something like ActiveSupport::OrderedHash (http://rubydoc.info/docs/rails/ActiveSupport/OrderedHash)
In Ruby 1.9.x hashes are ordered by when they are inserted by default (see http://www.ruby-doc.org/core/classes/Hash.html)
When you serialize a hash to JSON, all bets are off for maintaining order of your keys. You'll need some post processing after your serialization to ensure order if that's necessary for you.
No, hashmaps are not meant to have a specific ordering. If you need ordering use something different like an array. Or extract all the keys, sort them like you want and then you can have what order you like.
Making assumptions on ordering inside maps is anyway something on which you shouldn't rely, that's the fact.
A good alternative would be to have:
[ [a, aval], [b, bval], ... ]
Jack answered for Ruby, so I'll answer for JSON. From RFC 4627 (emphasis added):
"An object is an unordered collection of zero or more name/value pairs"

Resources