I have arrays basket = ["O", "P", "W", "G"] and sack = ["G", "P", "O", "W"]. How can I compare these arrays to determine if the elements are arranged in the same order on not?
You can use:
basket == sack #=> false, for given values
If you compare them, having the same order:
basket.sort == sack.sort #=> true
Also, please check "Comparing two arrays in Ruby" for a discussion on comparing arrays.
If both arrays can contain different number of elements and possibly some extra elements, and you want to find out whether those elements that are common to both arrays appear in exact same order, then, you could do something like below:
basket = ["D", "O", "P", "W", "G", "C"]
sack = ["Z", "O", "W", "P", "G", "X"]
p (basket - (basket - sack)) == (sack - (sack - basket))
Here is the solution I was able to come up with.
ordered = 0
disordered = 0
index = 0
while index < basket.length
if basket[index] == sack[index]
ordered+= 1
elsif basket.include?(sack[index]) && (basket[index] != sack[index])
disordered+= 1
end
index += 1
end
puts" there are #{ordered} ordered common items and #{disordered} disordered common items"
I hope it helps.
Related
I am trying to sort an array of letters alphabetically, but keep the special character in the same spot, in ruby.
For example,
word = ["f", "a", "s", "t", "-", "c", "a", "r", "s"]
How can I sort the whole thing alphabetically, but keep the "-" where it is. If I sort how it is now then the "-" will go to the front which I don't want. I have tried fifteen different ways, and I can't figure it out. Can you help?
Some really verbose way to do this, to explain the logic around what you need to achieve. There's some 'cleaner' methods to achieve this, but I feel this gives more understanding.
Adding an additional special character to the array for better test coverage:
let(:input) { ["f", "a", "s", "t", "-", "c", "a", "r", "s", "/"] }
let(:desired_output) { ["a", "a", "c", "f", "-", "r", "s", "s", "t", "/"] }
it "takes the input and gives the desired output" do
expect(sort_alphanumeric_characters(input)).to eq(desired_output)
end
Call .map and .select on the array to enumerate over the values and then call .with_index as you'll need to retain indicies for later.
def sort_alphanumeric_characters(word_as_array)
# assuming you mean non-alphanumeric
# collect those indicies which are 'special' characters
# the regex matches the string with anything outside of the alphanumeric range. Note the '^'
special_character_indicies = word_as_array.map.with_index { |val, indx| indx if val =~ /[^a-zA-Z0-9]/ }.compact
# collect all characters by index that were not yielded as 'special'
alphanumeric_array = word_as_array.select.with_index { |char, indx| char unless special_character_indicies.include? indx }
# sort the alphanumeric array
sorted_alphanumeric_array = alphanumeric_array.sort
# use Array#insert to place the 'special' by index
special_character_indicies.each do |special_indx|
special_char = word_as_array[special_indx]
sorted_alphanumeric_array.insert(special_indx, special_char)
end
# return desired output
sorted_alphanumeric_array
end
As soon as I posted I had a lightning bolt (love it when that happens). This is really not that great of a solution, but it did work!!
def scramble_words(str)
idx = 0
chars = str.delete("^a-z").chars
first_ele = chars.shift
last_ele = chars.pop
str.chars.each_with_index {|c, i| idx = i if c =~ /[^a-z" "]/ }
(first_ele + chars.sort.join + last_ele).insert(idx, str[idx])
end
p scramble_words('card-carrying') == 'caac-dinrrryg'
p scramble_words("shan't") == "sahn't"
p scramble_words('-dcba') == '-dbca'
So, I have a 2D array called allBusinesses of type BusinessClass. I fill this array in the following way:
allBusinesses[0].append(contentsOf: [B11, B12, B13, B14, B15, B16])
allBusinesses[1].append(contentsOf: [B21, B22, B23, B24, B25, B26])
Where B11, B12 ... B26 are all BusinessClass instances.
I have another 2D BusinessClass array called myOwnedBusinesses. I create it the following way:
var myOwnedBusinesses: [[BusinessClass]] = [[], []]
In my application, I have a tableView which contains all elements of allBusinesses, where each section contains the rows of the second dimension of the array, so that: allBusinesses[section][row]. When I select a random cell in the tableView, the corresponding BusinessClass element is added to the myOwnedBusinesses array, in the following way:
myOwnedBusinesses[selectedSection].append(allBusinesses[selectedSection][selectedRow])
As you can imagine from seeing the code, if I for instance select the cell at section 0 row 3, then select the cell at section 0 row 2, the order of myOwnedBusinesses will be wrong, being the opposite of what allBusinesses is. As a conclusion, I want to maintain the same order between the two arrays, even though the myOwnedBusinesses array is not always filled.
Here is my solution
let section0 = ["a", "b", "c", "d", "e", "f"]
let section1 = ["h", "i", "j", "k", "l", "m"]
section0.index(of: "b")
var all:[[String]] = [[],[]]
all[0].append(contentsOf: section0)
all[1].append(contentsOf: section1)
To keep the original indexes flatten the original array
let all_flat = all.flatMap {$0}
Let's say the user selects the cells in this order : "d", "e", "a", "h", "m", and "k".
var myArray = [["d", "e", "a"], ["h", "m", "k"]]
And then sort each array inside myArray
myArray = myArray.map {
$0.sorted { str1, str2 in
return all_flat.index(of: str1)! < all_flat.index(of: str2)!
}
}
For your case :
let allBusinesses_flat = allBusinesses.flatMap {$0}
myOwnedBusinesses = myOwnedBusinesses.map {
$0.sorted { b1, b2 in
return all_flat.index(of: b1)! < all_flat.index(of: b2)!
}
}
This solution is expensive, memory wise. Storing the selected indexes would be preferable.
I just started with Ruby. I need to build a method that takes two letters as arguments and returns an array of two arrays containing the same two letters and the letters included between them. The first array should contain only vowels whereas the second array only consonants. E.g.:
def alphamek('a', 'd')
should return:
[['a'], ['b', 'c', 'd']]
I tried this:
def alphamek(letter1, letter2)
first_array = (letter1..letter2).scan[aeiou].to_a
second_array = (letter1..letter2).scan[^aeiou].to_a
multi_array = [[first_array], [second_array]]
end
but it doesn't seem to work. Any ideas?
Not really that hard if you work it from a regular expression perspective and leverage a tool like partition:
VOWEL = /[aeiou]/i
def alphamek(a, b)
(a..b).partition { |l| VOWEL.match(l) }
end
Another way of doing that is to use the methods Array#& and Array#-.
VOWELS = %w| a e i o u |
#=> [“a“, ”e”, ”i”, ”o”, ”u”]
def doit(first_letter, last_letter)
letters = (first_letter..last_letter).to_a
[VOWELS & letters, letters - VOWELS]
end
doit 'f', 't'
#=> [["i", "o"], ["f", "g", "h", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t"]]
doit 'f', 'o'
#=> [["i", "o"], ["f", "g", "h", "j", "k", "l", "m", "n"]]
doit 'v', 'z'
#=> [[], ["v", "w", "x", "y", "z"]]
You are calling scan on the Range (letter1..letter2). That method does not exist.
What you can do is call select since Ranges are enumerable, see the documentation on an explanation for select: http://ruby-doc.org/core-2.5.0/Enumerable.html#method-i-select
Here's a working alternative that closely resembles your approach (as you intended it to work):
def alphamek(letter1, letter2)
vowels = 'aeiou'
# select all letters that are vowels
first_array = (letter1..letter2).select { |letter| vowels.include?(letter) }
# reject all letters that are vowels
second_array = (letter1..letter2).reject { |letter| vowels.include?(letter) }
return first_array, second_array # => [[...], [...]]
end
reject is simply the opposite of select, I prefer to use it instead of inverting the condition.
Anyway, there is an even better approach to this partitioning:
def alphamek(letter1, letter2)
vowels = 'aeiou'
(letter1..letter2).partition { |letter| vowels.include?(letter) }
end
This does the same as the other approach. partition splits the enumerable into two arrays, the first one contains the values for which the block evaluates to true, the second those for which it evaluates to false.
See partition in the docs: http://ruby-doc.org/core-2.5.0/Enumerable.html#method-i-partition
I'm trying to build a simple method to look at about 100 entries in a database for a last name and pull out all the ones that match above a specific percentage of letters. My current approach is:
Pull all 100 entries from the database into an array
Iterate through them while performing the following action
Split the last name into an array of letters
Subtract that array from another array that contains the letters for the name I am trying to match which leaves only the letters that weren't matched.
Take the size of the result and divide by the original size of the array from step 3 to get a percentage.
If the percentage is above a predefined threshold, push that database object into a results array.
This works, but I feel like there must be some cool ruby/regex/active record method of doing this more efficiently. I have googled quite a bit but can't find anything.
To comment on the merit of the measure you suggested would require speculation, which is out-of-bounds at SO. I therefore will merely demonstrate how you might implement your proposed approach.
Code
First define a helper method:
class Array
def difference(other)
h = other.each_with_object(Hash.new(0)) { |e,h| h[e] += 1 }
reject { |e| h[e] > 0 && h[e] -= 1 }
end
end
In short, if
a = [3,1,2,3,4,3,2,2,4]
b = [2,3,4,4,3,4]
then
a - b #=> [1]
whereas
a.difference(b) #=> [1, 3, 2, 2]
This method is elaborated in my answer to this SO question. I've found so many uses for it that I've proposed it be added to the Ruby Core.
The following method produces a hash whose keys are the elements of names (strings) and whose values are the fractions of the letters in the target string that are contained in each string in names.
def target_fractions(names, target)
target_arr = target.downcase.scan(/[a-z]/)
target_size = target_arr.size
names.each_with_object({}) do |s,h|
s_arr = s.downcase.scan(/[a-z]/)
target_remaining = target_arr.difference(s_arr)
h[s] = (target_size-target_remaining.size)/target_size.to_f
end
end
Example
target = "Jimmy S. Bond"
and the names you are comparing are given by
names = ["Jill Dandy", "Boomer Asad", "Josefine Simbad"]
then
target_fractions(names, target)
#=> {"Jill Dandy"=>0.5, "Boomer Asad"=>0.5, "Josefine Simbad"=>0.8}
Explanation
For the above values of names and target,
target_arr = target.downcase.scan(/[a-z]/)
#=> ["j", "i", "m", "m", "y", "s", "b", "o", "n", "d"]
target_size = target_arr.size
#=> 10
Now consider
s = "Jill Dandy"
h = {}
then
s_arr = s.downcase.scan(/[a-z]/)
#=> ["j", "i", "l", "l", "d", "a", "n", "d", "y"]
target_remaining = target_arr.difference(s_arr)
#=> ["m", "m", "s", "b", "o"]
h[s] = (target_size-target_remaining.size)/target_size.to_f
#=> (10-5)/10.0 => 0.5
h #=> {"Jill Dandy"=>0.5}
The calculations are similar for Boomer and Josefine.
I need to render the contents of the first 5 elements of an array and display "And X more" on a web page. Is there a built-in method on Array (or Enumerable) that easily separates one array into two sub-arrays: the first consisting of up to a fixed size and the second consisting of the array remainder?
I'm looking for one simple method call that will do this for me. Most of the methods that I looked at (like Enumerable#partition) use a logical condition to divide the array and don't supply the index to the block.
I just wrote the following code to do what I want. Please save me from myself and direct me to a method that already does it.
class Array
def bifurcate(size=length)
if size < 0
raise ArgumentError, "attempt to bifurcate using negative size"
end
remainder_size = length - size
if remainder_size < 0
remainder_size = 0
end
[
first(size),
last(remainder_size)
]
end
end
('a'..'g').to_a.bifurcate(2)
# => [["a", "b"], ["c", "d", "e", "f", "g"]]
('a'..'g').to_a.bifurcate(20)
# => [["a", "b", "c", "d", "e", "f", "g"], []]
('a'..'g').to_a.bifurcate()
# => [["a", "b", "c", "d", "e", "f", "g"], []]
('a'..'g').to_a.bifurcate(0)
# [[], ["a", "b", "c", "d", "e", "f", "g"]]
('a'..'g').to_a.bifurcate(-1)
# ArgumentError: attempt to bifurcate using negative size
Also, let me qualify that I want one simple method call to do what I want. Also consider that the starting array may contain duplicate values and this method needs to respect the original array and return duplicates.
You can use Enumerable#partition along with Enumerator#with_index method, as shown below:
size = 2
(1..6).partition.with_index { |_,i| i < size }
#=> [[1, 2], [3, 4, 5, 6]]
Alternatively, if your input array can be mutated, then, following will also do the trick
[array.shift(size), array]
[array.take(3), array.drop(3)]
# [["a", "b", "c"], ["d", "e", "f", "g"]]
Hope it helps :)
Use Array#[]:
[arr[0,size_of_first], arr[size_of_first..-1] || []]