Alphabetically sorting an array within an array in Ruby? - arrays

Method input:
["eat","tea","tan","ate","nat","bat"]
I have grouped each of the anagrams into their own array within an array through this method and then sorted the array by group size:
def group_anagrams(a)
a.group_by { |stringElement| stringElement.chars.sort }.values.sort_by(&:size)
end
I am struggling to figure out how to alphabetically sort the resulting arrays within the array here because as you can see nat should come before tan in the middle element of the array:
[["bat"], ["tan", "nat"], ["eat", "tea", "ate"]]
Updating with final solution:
def group_anagrams(a)
a.group_by { |stringElement| stringElement.chars.sort }.values.map(&:sort).sort_by(&:size)
end

You need to map this array and sort (map(&:sort))
def group_anagrams(ary)
ary.group_by { |s| s.chars.sort }.values.map(&:sort)
end
ary = ["eat", "tea", "tan", "ate", "nat", "bat"]
group_anagrams(ary)
# => [["ate", "eat", "tea"], ["nat", "tan"], ["bat"]]

Related

Sorting an array together with other array in jq

I have two arrays in a structure but between elements of arrays has logical connections. (Eg. comments[1] belongs to records[1], comments[2] belongs to records[2])
These arrays are sorted by alpabetical order of records array.
When I want to add a new element for both array then I have sort both arrays. For records array it is easy, but the elements of comments array have to move same way as each element of record.
Input:
{
"records":
[
{"content":"a"},
{"content":"z"}
],
"comments":[
{"content":"something"},
{"content":"anything"}
]
}
New elements are added to the end of arrays:
{
"records":[
{"content":"a"},
{"content":"z"},
{"content":"b"}
],
"comments":[
{"content":"something"},
{"content":"anything"},
{"content":"new element"}
]
}
Expected sorted output:
```json
{
"records":[
{"content":"a"},
{"content":"b"},
{"content":"z"}
],
"comments":[
{"content":"something"},
{"content":"new element"},
{"content":"anything"}
]
}
I tried "to_elements, map, transpose and addfunctions without any (partial) result.
Rather than appending the new elements to the arrays, you could use bsearch to find the insertion point, and then use that to perform the two insertions. Specifically, if $x is not in a sorted array, then the insertion point of $x in the array is -1 - bsearch($x).
You might find this helper function useful:
def insert($x;$i): .[:$i]+[$x]+.[$i:];
Solution
Here then is a solution for the problem at hand:
# It is assumed that (.|f) is a sorted array
def insert_into_sorted($x; f; $y; g):
def insert($x;$i): .[:$i]+[$x]+.[$i:];
(f|bsearch($x)) as $ix
| (if $ix > -1 then $ix else -1 - $ix end) as $i
| f|=insert($x; $i)
| g|=insert($y; $i) ;
insert_into_sorted( {"content": "b"}; .records;
{"content": "new element"}; .comments)

Working with Transpose functions result in error

consider the following array
arr = [["Locator", "Test1", "string1","string2","string3","string4"],
["$LogicalName", "Create Individual Contact","value1","value2"]]
Desired result:
[Test1=>{"string1"=>"value1","string2"=>"value2","string3"=>"","string4"=>""}]
When I do transpose, it gives me the error by saying second element of the array is not the length of the first element in the array,
Uncaught exception: element size differs (2 should be 4)
so is there any to add empty string in the place where there is no element and can perform the transpose and then create the hash as I have given above? The array may consist of many elements with different length but according to the size of the first element in the array, every other inner array has to change by inserting empty string and then I can do the transpose. Is there any way?
It sounds like you might want Enumerable#zip:
headers, *data_rows = input_data
headers.zip(*data_rows)
# => [["Locator", "$LogicalName"], ["Test1", "Create Individual Contact"],
# ["string1", "value1"], ["string2", "value2"], ["string3", nil], ["string4", nil]]
If you wish to transpose an array of arrays, each element of the array must be the same size. Here you would need to do something like the following.
arr = [["Locator", "Test1", "string1","string2","string3","string4"],
["$LogicalName", "Create Individual Contact","value1","value2"]]
keys, vals = arr
#=> [["Locator", "Test1", "string1", "string2", "string3", "string4"],
# ["$LogicalName", "Create Individual Contact", "value1", "value2"]]
idx = keys.index("Test1") + 1
#=> 2
{ "Test1" => [keys[idx..-1],
vals[idx..-1].
concat(['']*(keys.size - vals.size))].
transpose.
to_h }
#=> {"Test1"=>{"string1"=>"value1", "string2"=>"value2", "string3"=>"", "string4"=>""}}
It is not strictly necessary to define the variables keys and vals, but that avoids the need to create those arrays multiple times. It reads better as well, in my opinion.
The steps are as follows. Note keys.size #=> 6 and vals.size #=> 4.
a = vals[idx..-1]
#=> vals[2..-1]
#=> ["value1", "value2"]
b = [""]*(keys.size - vals.size)
#=> [""]*(4 - 2)
#=> ["", ""]
c = a.concat(b)
#=> ["value1", "value2", "", ""]
d = keys[idx..-1]
#=> ["string1", "string2", "string3", "string4"]
e = [d, c].transpose
#=> [["string1", "value1"], ["string2", "value2"], ["string3", ""], ["string4", ""]]
f = e.to_h
#=> {"string1"=>"value1", "string2"=>"value2", "string3"=>"", "string4"=>""}
f = e.to_h
#=> { "Test1" => f }
Find the longest Element in your Array and make sure every other element has the same length - loop and add maxLength - element(i).length amount of "" elements.

Iterate through an array and push elements into individual new arrays

I have an array:
["apple", "banana", "animal", "car", "angel"]
I want to push elements that start with "a" into separate arrays. I want to return:
["apple"], ["animal"], ["angel"]
I have only been able to make it work if I push them into an empty array that I pre-created.
Generally in order to pick elements from array that match some specific conditione use select method.
select returns an array of all elements that matched critera or an empty list in case neither element has matched
example:
new_array = array.select do |element|
return_true_or_false_depending_on_element(element)
end
now when we would like to put every element in its own array we could you another array method that is available on array - map which takes every element of an array and transforms it in another element. In our case we will want to take every matching string and wrap it in array
map usage:
new_array = array.map do |element|
element_transformation(element) # in order to wrap element just return new array with element like this: [element]
end
coming back to your question. in order to verify whether a string starts with a letter you could use start_with? method which is available for every string
glueing it all together:
strings = ["apple", "banana", "animal", "car", "angel"]
result = strings.select do |string|
string.start_with?("a")
end.map do |string_that_start_with_a|
[string_that_start_with_a]
end
puts result
Here's a golfed down version:
array.grep(/\Aa/).map(&method(:Array))
I might consider my audience before putting something this clever into production, since it can be a little confusing.
Array#grep returns all elements that match the passed regular expression, in this case /\Aa/ matches strings that begin with a. \A is a regular expression token that matches the beginning of the string. You could change it to /\Aa/i if you want it to be case insensitive.
The &method(:Array) bit grabs a reference to the kernel method Array() and runs it on each element of the array, wrapping each element in the array in its own array.
The simplest I can come up with is:
arr = %w{ apple banana animal car angel }
arr.map {|i| i.start_with?('a') ? [i] : nil }.compact
=> [["apple"], ["animal"], ["angel"]]
Here is some code I got to do this in console:
> arr = ["apple", "banana", "animal", "car", "angel"]
=> ["apple", "banana", "animal", "car", "angel"]
> a_words = []
=> []
arr.each do |word|
a_words << word if word.chars.first == 'a'
end
=> ["apple", "banana", "animal", "car", "angel"]
> a_words
=> ["apple", "animal", "angel"]
If you wanted to do something more complex than first letter you might want to use a regex like:
if word.matches(/\Aa/) # \A is beginning of string
array_of_arrays = []
your_array.each do |ele|
if ele.starts_with?("a")
array_of_arrays << ele.to_a
end
end

Ruby join two arrays by key value

I have two arrays, the first array contains field name, type and id.
arr1 = [
{
"n" => "cat",
"t" => 0,
"id" => "42WTd5"
},
{
"n" => "dog",
"t" => 0,
"id" => "1tM5T0"
}
]
Second array contains field, id and value.
arr2 = [
{
"42WTd5"=>"meow",
"1tM5T0"=>"woof"
}
]
How can I join them by id to produce the following result.
cat: meow
dog: woof
Any help is appreciated.
I think you want your result to be a Hash, in which case this would do the job:
def match_animals_to_sounds(animal_array, sound_array)
sounds = sound_array.first
animal_array.map { |animal| [animal['n'], sounds[animal['id']]] }.to_h
end
>> match_animals_to_sounds(arr1, arr2)
=> {"cat"=>"meow", "dog"=>"woof"}
Your arr2 is unusual in that it is an Array of a single element. I'm just calling #first on it to pull out the Hash inside. If you expect some version of this Array to have more than one element in the future, you'll need to rethink the first line of this method.
The second line is standard Ruby Array manipulation. The first part maps each animal to a new Array of two-element Arrays containing each animal's name and sound. At the end, #to_h converts this array of two-element arrays to a single Hash, which is much more useful than an array of strings. I don't know what you intended in your question, but this is probably what you want.
If you prefer to work with Symbols, you can change the second line of the method to:
animal_array.map { |animal| [animal['n'].to_sym, sounds[animal['id']].to_sym] }.to_h
In which case you will get:
>> match_animals_to_sounds(arr1, arr2)
=> {:cat=>:meow, :dog=>:woof}
This is a way to do it.
sounds = arr2[0]
results = arr1.map do |animal|
"#{animal["n"]}: #{sounds[animal["id"]]}"
end
puts results
# => cat: meow
# => dog: woof
Seems like the second array should just be a hash instead. There's no point creating an array if there's only one element in it and that number won't change.
pointless one-liner (don't use this)
puts arr1.map { |x| "#{x["n"]}: #{arr2[0][x["id"]]}" }
You can also get the join result by following code
arr1.collect{ |a| {a["n"] => arr2[0][a["id"]]} }

Ruby method to sum all values in a multidimensional array

I am trying to sum the elements of an array. WITHOUT using flatten. I have tried using the following:
def multi_array_sum(arr)
sum = 0
arr.each do |row|
row.each do |column|
sum += column
end
end
return sum
end
but unfortunately, it is not working. I am not sure how to iterate though a multidimensional array considering that I cannot use each if the first element in the array is not another array itself, for example, array = [[1, [1, 2], [3, 4, 5]].
If all elements are numeric or arrays, and you want to sum them all:
array.flatten.inject(:+)
Just use standard array functions and then enumerable.
array.flatten.reduce(:+)
If you are 100% sure that you cannot use flatten then you can use:
array.map { |a| a.reduce(:+) }.reduce(:+)
So if you absolutely can't use flatten (which is a bit weird), you can use a simple recursive method:
def multi_array_sum(arr)
case arr
when Fixnum
arr
when Array
arr.reduce(0) { |agg, sub_arr| agg + multi_array_sum(sub_arr) }
end
end
If each inner array is the same size and contains only numbers, you could use the method Matrix#[] to convert the array to a matrix, Matrix#each (without a block) to create an enumerator to generate the elements of the matrix, and Enumerable#reduce (aka inject) to compute the sum of all elements of the matrix.
require 'matrix'
def sum_all(arr)
Matrix[*arr].each.reduce(:+)
end
sum_all [[1,2],[3,4]] #=> 10

Resources