Ruby - how to pop a specific element from an array - ruby

What would be the easiest way in Ruby to pop a specific element from an array, similar to the .delete method of
a.delete(element)
rather than popping the first/last element or using .slice?
To make this more specific: for example, I can do
case names.sample when "John", "Dave", "Sam"
a.delete(names.sample)
end
to delete one of those names from a when it appears as a sample from names
However, I intend to use multiple samples and using a.delete()will remove all elements at once, rather than in succession like the result produced from shuffle!.pop where elements are popped in succession, so that the name can no longer be selected as a sample from a after the same name has been selected as a name.sample
I was wondering what the easiest way would be in Ruby to pop off these elements in succession, or if it is even possible at all in this context.

The Array class defines a pop method. It returns and deletes the last element in the array.
a = ["a", "b", "c"]
puts a.pop #=> "c"
puts a #=> ["a", "b"]
You can optionally pass an argument to pop that specifies how many elements to pop off.
a = ["a", "b", "c"]
puts a.pop(2) #=> ["b", "c"]
puts a #=> ["a"]
Addressing your last comment, you can use include?, index, and delete_at methods to achieve this. Assuming you're checking for "b" in an array:
a = ["a", "b", "c"]
value_index = a.index("b") #Returns the first occurring index of "b"
has_value = a.include?("b") #Returns whether "b" is in the list
a.delete_at(a.index("b")) if has_value #Removes "b" from the list
In this sample, "has_value" will be whether the a array contains the value "b", and "value_index" will be the first occurrence of "b". This will also delete the value "b" from the list.
If you want to remove all occurrences of "b", you can use include?, index, and delete_at with a while loop:
a = ["a", "b", "c", "a", "b", "c"]
while a.include?("b")
a.delete_at(a.index("b"))
end
#a will now be ["a", "c", "a", "c"]
See also the documentation for Array.

[..] intend to use multiple samples and using a.delete() will remove all elements at once, rather than in succession like the result produced from shuffle!.pop where elements are popped in succession, so that the name can no longer be selected as a sample from a after the same name has been selected as a name.sample[..]
Maybe you are looking something like this?
names = ["John", "Dave", "Sam"]
names.size.times { p names.delete(names.sample) }
#=> "Sam"
#=> "John"
#=> "Dave"

Related

How to extract each individual combination from a flat_map?

I'm fairly new to ruby and it's my first question here on stackoverflow so pardon me if I'm being a complete noob.
The code which i am working with contains this line -
puts (6..6).flat_map{|n| ('a'..'z').to_a.combination(n).map(&:join)}
What the code does is that its starts printing each of the combinations starting from "abcdef" and continues till the end (which i have never seen as it has 26^6 combinations).
Of course having an array of that size (26^6) is unimaginable hence I was wondering if there is any way by which i can get next combination in a variable, work with it, and then continue on to the next combination ?
For example I calculate the first combination as "abcdef" and store it in a variable 'combo' and use that variable somewhere and then the next combination is calculated and "abcdeg" is stored in 'combo' and hence the loop continues ?
Thanks
(6..6).flat_map { |n| ... } doesn't do much. Your code is equivalent to:
puts ('a'..'z').to_a.combination(6).map(&:join)
To process the values one by one, you can pass a block to combination:
('a'..'z').to_a.combination(6) do |combo|
puts combo.join
end
If no block is given, combination returns an Enumerator that can be iterated by calling next:
enum = ('a'..'z').to_a.combination(6)
#=> #<Enumerator: ["a", "b", "c", ..., "w", "x", "y", "z"]:combination(6)>
enum.next
#=> ["a", "b", "c", "d", "e", "f"]
enum.next
#=> ["a", "b", "c", "d", "e", "g"]
enum.next
#=> ["a", "b", "c", "d", "e", "h"]
Note that ('a'..'z').to_a.combination(6) will "only" yield 230,230 combinations:
('a'..'z').to_a.combination(6).size
#=> 230230
As opposed to 26 ^ 6 = 308,915,776. You are probably looking for repeated_permutation:
('a'..'z').to_a.repeated_permutation(6).size
#=> 308915776
Another way to iterate from "aaaaaa" to "zzzzzz" is a simple range:
('aaaaaa'..'zzzzzz').each do |combo|
puts combo
end
Or manually by calling String#succ: (this is what Range#each does under the hood)
'aaaaaa'.succ #=> "aaaaab"
'aaaaab'.succ #=> "aaaaac"
'aaaaaz'.succ #=> "aaaaba"

How to grab all values in a hash without specifying individual values in Ruby?

This is a add on for a question I asked yesterday but felt it warranted a new question.
I am taking a JSON response and want to extract all the values per iteration and put them into an array
#response = { "0"=>{"forename_1"=>"John", "surname_1"=>"Smith", forename_2"=>"Josephine", "surname_2"=>"Bradley", "middle_1"=>""},
"1"=>{"forename_1"=>"Chris", "surname_1"=>"Jenkins", forename_2"=>"Christine", "surname_2"=>"Sugar", "middle_1"=>""},
"2"=>{"forename_1"=>"Billy", "surname_1"=>"Bob", forename_2"=>"Brenda", "surname_2"=>"Goodyear", "middle_1"=>""},
"Status" => 100
}
At present this method takes specific values that I want and puts them into the array I want.
col = #response.values.grep(Hash).map { |h| "#{h['forename_1']} #{h['surname_1']} #{h['forename_2']} #{h['surname_2']} #{h['middle_1']}" }
Is there a way however to say grab ALL the values and place them into an array (I have a response where over 25 key/value pairs are returned).
At the moment if middle_1 has no value then a " " gets put into the array, ideally I would like to remove these.
Ideally I would like my newly formed array to look like
["John Smith Josephine Bradley", "Chris Jenkins Christine Sugar", "Billy Bob Brenda Goodyear"]
Even though no middle_1 is supplied there is are no double spaces in the array. I would like to learn how to tackle this.
Maybe will provide example of "cracking" the hash and extracting what you would need:
h = {a1: "a", b2: "b", c3: "", d4: nil, e5: "e"}
values = h.values.map(&:to_s).reject(&:empty?)
# => ["a", "b", "e"]
values.join(" ")
# => "a b e"
Let's consider the h.values.map(&:to_s).reject(&:empty?):
values = h.values
# => ["a", "b", "", nil, "e"]
values = values.map(&:to_s)
# => ["a", "b", "", "" "e"]
values = values.reject(&:empty?)
# => ["a", "b", "e"]
Hope that gives you some idea how you can proceed.
Good luck!
UPDATE
For provided hash you can quite easily reuse what I have described above like:
col = #response.values
.grep(Hash)
.map { |h| h.values.map(&:to_s).reject(&:empty?).join(" ") }
p col
# => ["John Smith Josephine Bradley", "Chris Jenkins Christine Sugar", "Billy Bob Brenda Goodyear"]

How to sort! arrays in ruby

I want to sort my_array and then reverse the order.
Which markup is correct?
my_array.sort.reverse!
or
my_array.sort!.reverse
Or does it make any difference?
Thanks
You have to decompose the chain :
First, let's understand the difference between the sort and the sort! method.
If I write
array = [7,2,4]
array.sort!
array # => [2,4,7]
If you write
array = [7,2,4]
foo = array.sort
array # => [7,2,4]
foo # => [2,4,7]
The sort method sort the array and returns the result as the output of the function, whereas the sort! one directly modifies the existing array.
So if you write :
my_array.sort.reverse!
It is like writing :
(my_array.sort). # => Here we create a new array who is calculated by sorting the existing one
reverse! # => Then we reverse this new array, who is not referenced by a variable.
If you write :
(my_array.sort!). #=> Here you sort my_array and reinject the result into my_array !
reverse # Then reverse it and inject the result into a NEW array
So in both cases, you will not obtain what you want ! What you want to do is either :
my_array.sort!.reverse!
or :
new_array = my_array.sort.reverse
You'll get the same output, but one will modify the initial array. See this:
2.1.1 :001 > my_array = ["a","d","b","c"]
=> ["a", "d", "b", "c"]
Just declaring an array with a, b, c, and d in completely wrong orders.
2.1.1 :002 > my_array.sort.reverse!
=> ["d", "c", "b", "a"]
Running your first command on it returns a reverse-sorted array
2.1.1 :003 > my_array
=> ["a", "d", "b", "c"]
... but doesn't modify the original array itself.
2.1.1 :004 > my_array.sort!.reverse
=> ["d", "c", "b", "a"]
Running the second command returns the same result, the array sorted backwards
2.1.1 :005 > my_array
=> ["a", "b", "c", "d"]
But the array itself has been modified, but only by the sort! call. A ! after a method call 'saves' the changes to the object it's called on and returns the result. So in the second one:
You sort the array, saving the changes to it and returning the sorted array, then
Run reverse on the sorted array, which doesn't save to anything and only returns the result.
my_array.sort!.reverse will modify the receiver so my_array will be sorted after this call e.g.
my_array = [1,4,3,5,2]
my_array.sort!.reverse
#=> [5,4,3,2,1]
my_array
#=> [1,2,3,4,5]
the second form my_array.sort.reverse! will not modify my_array because sort will dup the array first then reverse! will modify this duped copy which is not being stored. This would have the same impact as my_array.sort.reverse without the !
my_array = [1,4,3,5,2]
my_array.sort.reverse!
#=> [5,4,3,2,1]
my_array
#=> [1,4,3,5,2]
Thirdly, something like my_array.sort!.reverse! will modify the receiver twice meaning my_array.sort! will sort the array in place and then .reverse! will reverse the array in place. so my_array will now be sorted and reversed.
my_array = [1,4,3,5,2]
my_array.sort!.reverse!
#=> [5,4,3,2,1]
my_array
#=> [5,4,3,2,1]
Although in this case I do not think you will need either bang ! method as the second form has no impact. bang ! in ruby means "dangerous", may alter the data or have other unexpected results.
my_array.sort!.reverse!
is the correct answer, since you want to change the array you already have.
my_array.sort.reverse!
creates a sorted copy and reverses it (the original doesn't change).
my_array.sort!.reverse
sorts the original and creates a reversed copy (the original isn't reversed).

When changing the $LOAD_PATH, why do you use unshift instead of push?

I find ruby load path is an array, and many projects use it like this:
$:.unshift(File.expand_path("../../lib", __FILE__))
It can add local files to the front of ruby path array to enable us require or load.
So, I hope to know why don't we use push to add the file at the end of the array?
Let's assume you have a "date.rb" file (why not) and you want to load this file, and not the standard library date.
If you use append, your file will never be loaded when you call require 'date' because it's located at the end of the array and the standard date will be found before.
Therefore, if you prepend your path to the load path, you don't risk priority lookup
This is because concat is to add one array to another. With unshift you add any item to the beginning of a list. And in case of load-paths, order is impiortant, so adding it to the beginning is important, hence e.g. a shovel <<(), adding an item to the end, will not suffice:
["a", "b"].concat(["c", "d"]) #=> ["a", "b", "c", "d"]
["a", "b"].unshift("c").unshift("d") #=> ["d", "c", "a", "b"]
["a", "b"] << "c" << "d" #=> ["a", "b", "c", "d"]
First, get the lib directory:
File.expand_path("../../lib", __FILE__)
#=> "/home/foo/lib/" #Note this is a string!
Then add that to $:., containing the current load paths. E.g:
$:.
#=> ["/usr/local/lib/site_ruby/1.9.1", "/usr/lib/ruby/1.9.1/i686-linux"]
By unshifting it, you add it to the beginning of the list of load paths:
$:.unshift(File.expand_path("../../lib", __FILE__))
#=> ["/home/foo/lib", "/usr/local/lib/site_ruby/1.9.1", "/usr/lib/ruby/1.9.1/i686-linux"]
Whereas, a concat would not only add it to the end, it would also require some additional ugly syntax, [] around the string to pass it along as an item from an array:
$:.concat([File.expand_path("../../lib", __FILE__)])
#=> ["/usr/local/lib/site_ruby/1.9.1", "/usr/lib/ruby/1.9.1/i686-linux", "/home/lib"]

Determining if a prefix exists in a set

Given a set of strings, say:
"Alice"
"Bob"
"C"
"Ca"
"Car"
"Carol"
"Caroling"
"Carousel"
and given a single string, say:
"Carolers"
I would like a function that returns the smallest prefix not already inside the array.
For the above example, the function should return: "Caro". (A subsequent call would return "Carole")
I am very new to Ruby, and although I could probably hack out something ugly (using my C/C++/Objective-C brain), I would like to learn how to properly (elegantly?) code this up.
There's a little known magical module in Ruby called Abbrev.
require 'abbrev'
abbreviations = Abbrev::abbrev([
"Alice",
"Bob",
"C",
"Ca",
"Car",
"Carol",
"Caroling",
"Carousel"
])
carolers = Abbrev::abbrev(%w[Carolers])
(carolers.keys - abbreviations.keys).sort.first # => "Caro"
Above I took the first element but this shows what else would be available.
pp (carolers.keys - abbreviations.keys).sort
# >> ["Caro", "Carole", "Caroler", "Carolers"]
Wrap all the above in a function, compute the resulting missing elements, and then iterate over them yielding them to a block, or use an enumerator to return them one-by-one.
This is what is generated for a single word. For an array it is more complex.
require 'pp'
pp Abbrev::abbrev(['cat'])
# >> {"ca"=>"cat", "c"=>"cat", "cat"=>"cat"}
pp Abbrev::abbrev(['cat', 'car', 'cattle', 'carrier'])
# >> {"cattl"=>"cattle",
# >> "catt"=>"cattle",
# >> "cat"=>"cat",
# >> "carrie"=>"carrier",
# >> "carri"=>"carrier",
# >> "carr"=>"carrier",
# >> "car"=>"car",
# >> "cattle"=>"cattle",
# >> "carrier"=>"carrier"}
Your question still doesn't match what you are expecting as a result. It seems that you need prefixes, not the substrings (as "a" would be the shortest substring not already in the array). For searching the prefix, this should suffice:
array = [
"Alice",
"Bob",
"C",
"Ca",
"Car",
"Carol",
"Caroling",
"Carousel",
]
str = 'Carolers'
(0..str.length).map{|i|
str[0..i]
}.find{|s| !array.member?(s)}
I am not a Ruby expert, but I think you may want to approach this problem by converting your set into a trie. Once you have the trie constructed, your problem can be solved simply by walking down from the root of the trie, following all of the edges for the letters in the word, until you either find a node that is not marked as a word or walk off the trie. In either case, you've found a node that isn't part of any word, and you have the shortest prefix of your word in question that doesn't already exist inside of the set. Moreover, this would let you run any number of prefix checks quickly, since after you've built up the trie the algorithm takes time at most linear in the length of the string.
Hope this helps!
I'm not really sure what you're asking for other than an example of some Ruby code to find common prefixes. I'll assume you want to find the smallest string which is a prefix of the most number of strings in the given set. Here's an example implementation:
class PrefixFinder
def initialize(words)
#words = Hash[*words.map{|x|[x,x]}.flatten]
end
def next_prefix
max=0; biggest=nil
#words.keys.sort.each do |word|
0.upto(word.size-1) do |len|
substr=word[0..len]; regex=Regexp.new("^" + substr)
next if #words[substr]
count = #words.keys.find_all {|x| x=~regex}.size
max, biggest = [count, substr] if count > max
#puts "OK: s=#{substr}, biggest=#{biggest.inspect}"
end
end
#words[biggest] = biggest if biggest
biggest
end
end
pf = PrefixFinder.new(%w(C Ca Car Carol Caroled Carolers))
pf.next_prefix # => "Caro"
pf.next_prefix # => "Carole"
pf.next_prefix # => "Caroler"
pf.next_prefix # => nil
No comment on the performance (or correctness) of this code but it does show some Ruby idioms (instance variables, iteration, hashing, etc).
=> inn = ["Alice","Bob","C","Ca","Car","Carol","Caroling","Carousel"]
=> y = Array.new
=> str="Carolers"
Split the given string to an array
=> x=str.split('')
# ["C","a","r","o","l","e","r","s"]
Form all the combination
=> x.each_index {|i| y << x.take(i+1)}
# [["c"], ["c", "a"], ["c", "a", "r"], ["c", "a", "r", "o"], ["c", "a", "r", "o", "l"], ["c", "a", "r", "o", "l", "e"], ["c", "a", "r", "o", "l", "e", "r"], ["c", "a", "r", "o", "l", "e", "r", "s"]]
Using Join to concatenate the
=> y = y.map {|s| s.join }
# ["c", "ca", "car", "caro", "carol", "carole", "caroler", "carolers"]
Select the first item from the y thats not available in the input Array
=> y.select {|item| !inn.include? item}.first
You will get "caro"
Putting together all
def FindFirstMissingItem(srcArray,strtocheck)
y=Array.new
x=strtocheck.split('')
x.each_index {|i| y << x.take(i+1)}
y=y.map {|s| s.join}
y.select {|item| !srcArray.include? item}.first
end
And call
=> inn = ["Alice","Bob","C","Ca","Car","Carol","Caroling","Carousel"]
=> str="Carolers"
FindFirstMissingItem inn,str
Very simple version (but not very Rubyish):
str = 'Carolers'
ar = %w(Alice Bob C Ca Car Carol Caroling Carousel)
substr = str[0, n=1]
substr = str[0, n+=1] while ar.include? substr
puts substr

Resources