I have an array:
a = ["http://design.example.com", "http://www.domcx.com", "http://subr.com"]
and then I want to return true if one of the elements in that array matches the string:
s = "example.com"
I tried with include? and any?.
a.include? s
a.any?{|w| s=~ /#{w}/}
I don't know how to use it here. Any suggestions?
You can use any? like:
[
"http://design.example.com",
"http://www.domcx.com",
"http://subr.com"
].any?{ |s| s['example.com'] }
Substituting your variable names:
a = [
"http://design.example.com",
"http://www.domcx.com",
"http://subr.com"
]
s = "example.com"
a.any?{ |i| i[s] }
You can do it several other ways also, but the advantage using any? is it will stop as soon as you get one hit, so it can be much faster if that hit occurs early in the list.
How is the below:
a=["http://design.example.com", "http://www.domcx.com", "http://subr.com"]
s= "sus"
p a.any? { |w| w.include? s } #=> false
a=["http://design.example.com", "http://www.domcx.com", "http://subr.com"]
s= "design.example"
p a.any? { |w| w.include? s } #=>true
a=["http://design.example.com", "http://www.domcx.com", "http://subr.com"]
s= "desingn.example"
p a.any? { |w| w.include? s } #=>false
a=["http://design.example.com", "http://www.domcx.com", "http://subr.com"]
s= "example"
p a.any? { |w| w.include? s } #=>true
a=["http://design.example.com", "http://www.domcx.com", "http://subr.com"]
s= "example.com"
p a.any? { |w| w.include? s } #=>true
Related
I have an array of paths:
paths = ["home", "usr/lib/folder1/", "usr/lib/folder2/"]
I tried to make a tree with full path on the ends (leaves):
{"home" => "home", "usr" => {"lib" => {"folder1" => "usr/lib/folder1/", "folder2" => "usr/lib/folder2/"}}}
This is my code:
paths.each do |path|
current = tree
path.split('/').inject('') do |_sub_path, dir|
sub_path = File.join(dir)
current[sub_path] ||= {path => {}}
current = current[sub_path]
sub_path
end
end
Can you show me the right way for my question?
This is my first question on SO. Sorry if my English bad.
This will do it but its not tested nor is it very Rubyish...
paths = ["home", "usr/lib/folder1/", "usr/lib/folder2/"]
ans =
paths.reduce({}){
|acc, e|
last = e.split('/').last
e.split('/').reduce(acc){
|acc, n|
acc[n] = {} if acc[n].nil?
acc[n] = e if n == last
acc[n]
}
acc
}
p ans
What's your strategy for adding more paths?I.E. If you have to add another path like "home/user/data" and "/home/user/docs" or "usr/lib/folder1/data" and "usr/lib/folder2/data", what's your strategy?
This could be solved recursively.
def recurse(arr, arr_build = [])
return arr_build.join('/') if arr == [[]]
arr.group_by { |a| a.first }.
transform_values { |v| recurse(v.map { |a| a.drop(1) },
arr_build + [v.first.first]) }
end
recurse(paths.map { |s| s.split('/') })
#=> {"home"=>"home",
# "usr"=>{"lib"=>{"folder1"=>"usr/lib/folder1",
# "folder2"=>"usr/lib/folder2"}}}
See Enumerable#group_by and Hash#transform_values.
Note that when
arr = paths.map { |s| s.split('/') }
#=> [["home"], ["usr", "lib", "folder1"], ["usr", "lib", "folder2"]]
we find that
arr.group_by { |a| a.first }
#=> {"home"=>[["home"]],
# "usr"=>[["usr", "lib", "folder1"], ["usr", "lib", "folder2"]]}
str = "<a><b><c></c></b></a>"
hash = Hash.from_xml(str)
# => {"a"=>{"b"=>{"c"=>nil}}}
How can I replace all nils in a Hash to "" so that the hash becomes:
{"a"=>{"b"=>{"c"=>""}}}
Here is a recursive method that does not change the original hash.
Code
def denilize(h)
h.each_with_object({}) { |(k,v),g|
g[k] = (Hash === v) ? denilize(v) : v.nil? ? '' : v }
end
Examples
h = { "a"=>{ "b"=>{ "c"=>nil } } }
denilize(h) #=> { "a"=>{ "b"=>{ "c"=>"" } } }
h = { "a"=>{ "b"=>{ "c"=>nil , "d"=>3, "e"=>nil}, "f"=>nil } }
denilize(h) #=> { "a"=>{ "b"=>{ "c"=>"" , "d"=>3, "e"=>""}, "f"=>"" } }
this will destroy the original hash and will not work with hashes with infinite recursion.
def nil2empty(hash)
hash.keys.each do |key|
if hash[key].kind_of? Hash
nil2empty(hash[key])
else
hash[key] = '' if hash[key].nil?
end
end
true # of course, what else? :P
end
example of usage:
hash
=> {"a"=>{"b"=>{"c"=>nil}}}
nil2empty(hash)
=> true
hash
=> {"a"=>{"b"=>{"c"=>""}}}
I know this is not the answer you are expecting, but if you could handle a value instead of "" , this code works
eval({"a"=>{"b"=>{"c"=>nil}}}.to_s.gsub("nil", "1")) #=> returns a hash #{"a"=>{"b"=>{"c"=>1}}}
I have a string like this,
str = "uu#p, xx#m, yy#n, zz#m"
I want to know how to convert the given string into a hash. (i.e my actual requirement is, how many values (before the # symbol) have the m, n and p. I don't want the counting, I need an exact value). The output would be better like this,
{"m" => ["xx", "zz"], "n" => ["yy"], "p" => ["uu"]}
Can help me anyone, please?
Direct copy/past of an IRB session:
>> str.split(/, /).inject(Hash.new{|h,k|h[k]=[]}) do |h, s|
.. v,k = s.split(/#/)
.. h[k] << v
.. h
.. end
=> {"p"=>["uu"], "m"=>["xx", "zz"], "n"=>["yy"]}
Simpler code for a newbie :)
str = "uu#p, xx#m, yy#n, zz#m"
h = {}
str.split(",").each do |x|
v,k = x.split('#')
h[k] ||= []
h[k].push(v)
end
p h
FP style:
grouped = str
.split(", ")
.group_by { |s| s.split("#")[1] }
.transform_values { |ss| ss.map { |x| s.split("#")[0] } }
#=> {"m"=>["xx", "zz"], "n"=>["yy"], "p"=>["uu"]}
This is a pretty common pattern. Using Facets.map_by:
require 'facets'
str.split(", ").map_by { |s| s.split("#", 2).reverse }
#=> {"m"=>["xx", "zz"], "n"=>["yy"], "p"=>["uu"]}
I have a simple array:
arr = ["apples", "bananas", "coconuts", "watermelons"]
I also have a function f that will perform an operation on a single string input and return a value. This operation is very expensive, so I would like to memoize the results in the hash.
I know I can make the desired hash with something like this:
h = {}
arr.each { |a| h[a] = f(a) }
What I'd like to do is not have to initialize h, so that I can just write something like this:
h = arr.(???) { |a| a => f(a) }
Can that be done?
Say you have a function with a funtastic name: "f"
def f(fruit)
fruit + "!"
end
arr = ["apples", "bananas", "coconuts", "watermelons"]
h = Hash[ *arr.collect { |v| [ v, f(v) ] }.flatten ]
will give you:
{"watermelons"=>"watermelons!", "bananas"=>"bananas!", "apples"=>"apples!", "coconuts"=>"coconuts!"}
Updated:
As mentioned in the comments, Ruby 1.8.7 introduces a nicer syntax for this:
h = Hash[arr.collect { |v| [v, f(v)] }]
Did some quick, dirty benchmarks on some of the given answers. (These findings may not be exactly identical with yours based on Ruby version, weird caching, etc. but the general results will be similar.)
arr is a collection of ActiveRecord objects.
Benchmark.measure {
100000.times {
Hash[arr.map{ |a| [a.id, a] }]
}
}
Benchmark #real=0.860651, #cstime=0.0, #cutime=0.0, #stime=0.0, #utime=0.8500000000000005, #total=0.8500000000000005
Benchmark.measure {
100000.times {
h = Hash[arr.collect { |v| [v.id, v] }]
}
}
Benchmark #real=0.74612, #cstime=0.0, #cutime=0.0, #stime=0.010000000000000009, #utime=0.740000000000002, #total=0.750000000000002
Benchmark.measure {
100000.times {
hash = {}
arr.each { |a| hash[a.id] = a }
}
}
Benchmark #real=0.627355, #cstime=0.0, #cutime=0.0, #stime=0.010000000000000009, #utime=0.6199999999999974, #total=0.6299999999999975
Benchmark.measure {
100000.times {
arr.each_with_object({}) { |v, h| h[v.id] = v }
}
}
Benchmark #real=1.650568, #cstime=0.0, #cutime=0.0, #stime=0.12999999999999998, #utime=1.51, #total=1.64
In conclusion
Just because Ruby is expressive and dynamic, doesn't mean you should always go for the prettiest solution. The basic each loop was the fastest in creating a hash.
h = arr.each_with_object({}) { |v,h| h[v] = f(v) }
Ruby 2.6.0 enables a shorter syntax by passing a block to the to_h method:
arr.to_h { |a| [a, f(a)] }
This is what I would probably write:
h = Hash[arr.zip(arr.map(&method(:f)))]
Simple, clear, obvious, declarative. What more could you want?
I'm doing it like described in this great article http://robots.thoughtbot.com/iteration-as-an-anti-pattern#build-a-hash-from-an-array
array = ["apples", "bananas", "coconuts", "watermelons"]
hash = array.inject({}) { |h,fruit| h.merge(fruit => f(fruit)) }
More info about inject method: http://ruby-doc.org/core-2.0.0/Enumerable.html#method-i-inject
Another one, slightly clearer IMHO -
Hash[*array.reduce([]) { |memo, fruit| memo << fruit << f(fruit) }]
Using length as f() -
2.1.5 :026 > array = ["apples", "bananas", "coconuts", "watermelons"]
=> ["apples", "bananas", "coconuts", "watermelons"]
2.1.5 :027 > Hash[*array.reduce([]) { |memo, fruit| memo << fruit << fruit.length }]
=> {"apples"=>6, "bananas"=>7, "coconuts"=>8, "watermelons"=>11}
2.1.5 :028 >
in addition to the answer of Vlado Cingel (I cannot add a comment yet, so I added an answer).
Inject can also be used in this way: the block has to return the accumulator. Only the assignment in the block returns the value of the assignment, and an error is reported.
array = ["apples", "bananas", "coconuts", "watermelons"]
hash = array.inject({}) { |h,fruit| h[fruit]= f(fruit); h }
ruby
i have the following
p = 0
[s1.size,s2.size].max.times { |c| if s1[c] == s2[c]; p = c; else break; end };
matched_part = s1[0..p]
but i dont know how i can this for multiple strings (more than 2) at the same time.
Alright, how's this?
class String
def self.overlap(s1,s2,*strings)
strings += [s2]
strings.min { |s| s.size }.size.times do |n|
return s1[0,n] unless strings.all? { |string| s1[n]==string[n] }
end
s1
end
end
class String
def self.overlap(first,second,*others)
s1 = first
others = [second] + others
others.each do |s2|
p = 0
s1.length.times { |c| if s1[c] == s2[c] then p = c else break end }
s1 = s1[0..p]
end
s1
end
end
puts String.overlap "marry had a little lamb", "marry had a bug dog", "marry had a cat", "marry had a bird OUT:", "marry had something" #=> marry had
In one line:
strings[0].slice(0,(0...strings[0].size).find {|i| strings.map {|s| s[i..i]}.uniq.size > 1})