Iterate through an array and push elements into individual new arrays - 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

Related

Alphabetically sorting an array within an array in Ruby?

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"]]

Algorith to remove elements from array one by one based on index

This is a simplification to the purest case of a problem in a embedded system with arbitrary limits that i cannot control
Let there be an array of anything, for example words:
["apple", "pear", "banana", "orange"]
Let there be an array of indexes (starting at one) to remove items from:
[1,3]
We need a function that returns the result of removing those indexes from the starting array, in this example the result should be:
["pear", "orange"]
as it removed indexes 1 and 3
However, the only accepted operation to achieve that is a function that removes one item by index from the array, and mutates it, for example:
We have the original array ["apple", "pear", "banana", "orange"]
We want to remove items [1,3]
We removeItem(1)
The result is ["pear", "banana", "orange"]
The next item we want to remove is the item at index 3 of the original array, which is "banana", however, the item at current index 3 is "orange", thus, the naive approach to remove items does not work, as it will result in removing "orange" instead, with a final result of:
["pear", "banana"] instead of ["pear", "orange"]
If the indices are sorted, then you simply need to decrease the index by one each time you remove an element:
for i = 1 .. len(indices)
elements.removeItem(indices[i] - i + 1)
Alternatively, delete the items backwards. This is probably also more efficient depending on the implementation of the removal process:
for i = len(indices) .. 1
elements.removeItem(indices[i])

How to print from two lists on swift

If I have a list of first names, and then a list of second names then how do I print a random selection from 1 of each list
let arrayX = ["James", "Andrew", "Sean"]
let arrayY = ["Smith", "Docherty", "Anderson"]
So I could have James Smith, or Andrew Anderson?
Fetch String with randomly generated index.
let arrayX = ["James", "Andrew", "Sean"]
let arrayY = ["Smith", "Docherty", "Anderson"]
print(arrayX[getRandomIndex(maxRange: arrayX.count)], arrayY[getRandomIndex(maxRange: arrayY.count)])
Function to generate random index:
func getRandomIndex(maxRange: Int) -> Int{
return Int(arc4random_uniform(UInt32(maxRange)))
}
To select a random item from an array you need to generate a random number within it's index range.
You can do this in Swift using arc4random_uniform:
Int(arc4random_uniform(UInt32(arrayX.count)))
Once you know how to do this you can quite easily generate a random name from your arrays:
let arrayX = ["James", "Andrew", "Sean"]
let arrayY = ["Smith", "Docherty", "Anderson"]
let randomForenameIdx = Int(arc4random_uniform(UInt32(arrayX.count)))
let randomSurnameIdx = Int(arc4random_uniform(UInt32(arrayY.count)))
let randomName = "\(arrayX[randomForenameIdx]) \(arrayY[randomSurnameIdx])"
Swift has a very nice way of intertwining arrays using the zip function:
let firstNames = ["James", "Andrew", "Sean"]
let lastNames = ["Smith", "Docherty", "Anderson"]
let randomIndex = Int(arc4random_uniform(UInt32(firstNames.count)))
let randomName = Array(zip(firstNames, lastNames))[randomIndex]
print("\(randomName.0) \(randomName.1)")
zip(_:_:) takes two collections (i. e. arrays) and returns a sequence of tuple pairs, where the elements of each pair are corresponding elements of both collections. The Array initialiser converts the result to an Array of tuples.
This solution always matches first and last names, i. e. you either get James Smith, Andrew Doherty, or Sean Anderson. If this is not what you want then you’ll need two random indexes and no zip function, as suggested in the other answers.

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"]]} }

Randomly select 5 elements from an array list without repeating an element

I am currently trying to make an app for iOS but I can't get some simple code down. Basically I need to randomly select 5 elements from an array list without repeating an element. I have a rough draft, but it only displays one element.
Here is my code:
let array1 = ["salmon", "turkey", "salad", "curry", "sushi", "pizza"]
let randomIndex1 = Int(arc4random_uniform(UInt32(array1.count)))
print(array1[randomIndex1])
You can do it like this:
let array1 = ["salmon", "turkey", "salad", "curry", "sushi", "pizza", "curry", "sushi", "pizza"]
var resultSet = Set<String>()
while resultSet.count < 5 {
let randomIndex = Int(arc4random_uniform(UInt32(array1.count)))
resultSet.insert(array1[randomIndex])
}
let resultArray = Array(resultSet)
print(resultArray)
A set can contain unique elements only, so it can't have the same element more than once.
I created an empty set, then as long as the array contains less than 5 elements (the number you chose), I iterated and added a random element to the set.
In the last step, we need to convert the set to an array to get the array that you want.
SWIFT 5.1
This has been answered, but I dare to come with a more simple solution.
If you take your array and convert it into a Set you will remove any duplicated items and end up with a set of unique items in no particular order since the nature of a Set is unordered.
https://developer.apple.com/documentation/swift/set
If you then convert it back to an array and pick 5 elements you will end up with an array of random items.
But it's just 1 line ;)
Example:
var original = ["A","B","C","C","C","D","E","F","G","H"]
let random = Array(Set(original)).prefix(5)
Example print:
["B", "G", "H", "E", "C"]
The only requirement is your objects must conform to the Hashable protocol. Most standard Swift types do, otherwise, it's often simple to make your own types conform.
https://developer.apple.com/documentation/swift/hashable
If you don't care about changing the original array, the following code will put the picked elements at the end of the array and then it will return the last part of the array as a slice.
This is useful if you don't care about changing the original array, the advantage is that it doesn't use extra memory, and you can call it several times on the same array.
extension Array {
mutating func takeRandomly(numberOfElements n: Int) -> ArraySlice<Element> {
assert(n <= self.count)
for i in stride(from: self.count - 1, to: self.count - n - 1, by: -1) {
let randomIndex = Int(arc4random_uniform(UInt32(i + 1)))
self.swapAt(i, randomIndex)
}
return self.suffix(n)
}
}
Example:
var array = [1,2,3,4]
let a1 = array.takeRandomly(numberOfElements: 2)
let a2 = array.takeRandomly(numberOfElements: 2)
swift-algorithms now includes an extension to Sequence called randomSample.
import Algorithm
var array1 = ["salmon", "turkey", "salad", "curry", "sushi", "pizza"]
array1.randomSample(count: 5)
Just my ¢2:
Moe Abdul-Hameed's solution has one theoretical drawback: if you roll the same randomIndex in every iteration, the while loop will never exit. It's very unlike tho.
Another approach is to create mutable copy of original array and then exclude picked items:
var source = array1
var dest = [String]()
for _ in 1...5 {
let randomIndex = Int(arc4random_uniform(UInt32(source.count)))
dest.append(source[randomIndex])
source.remove(at: randomIndex)
}
print(dest)
var array1 = ["salmon", "turkey", "salad", "curry", "sushi", "pizza"]
while array1.count > 0 {
// random key from array
let arrayKey = Int(arc4random_uniform(UInt32(array1.count)))
// your random number
let randNum = array1[arrayKey]
// make sure the number ins't repeated
array1.removeAtIndex(arrayKey)
}
By removing your picked value from array, prevent's from duplicates to be picked

Resources