convert array of object to array of integer in ruby - arrays

So I want to convert in ruby
[{:user_id => 4}, {:user_id => 22}, {:user_id=>51}, {:user_id=>52}]
to
[4, 22, 51, 52]
Is there way of convert this?

As simple as possible: array.flat_map(&:values)

Very simple, let's use map to transform each item in something else
array.map { |item| item[:user_id] }
=> [4, 22, 51, 52]

Related

Merging multiple arrays and get an array of common elements as output

I'm trying to merge several arrays in javascript/typescript in angular, I need to output an array with the common values in all the arrays.
for eg:
arrayOne = [34, 23, 80, 93, 48]
arrayTwo = [48, 29, 10, 79, 23]
arrayThree = [23, 89, 48, 20, 63]
output: outputArr= [23, 48]
for getting common elements out of 2 arrays i'm filtering one array with the element from the next array.
return this.arrayOne.filter(el => this.arrayTwo.includes(el));
How do I do it effectively if I have to combine large number of arrays....?
Thanks in advance...
You could use multiple Set to quickly look up for each value among the different sets.
const intersection = <T>(arrays: T[][]): T[] => {
if (arrays.length == 0) return [];
if (arrays.length == 1) return arrays[0];
const sets = arrays.slice(1).map(array => new Set(array));
const result = [];
arrays[0].forEach(item => {
if (sets.every(set => set.has(item))) {
result.push(item);
}
});
return result;
};
const arrayOne = [34, 23, 80, 93, 48];
const arrayTwo = [48, 29, 10, 79, 23];
const arrayThree = [23, 89, 48, 20, 63];
const result = intersection([arrayOne, arrayTwo, arrayThree]);
console.log(result);
One approach is to create an initial set that contains the first array's elements. Then loop over the other arrays, converting them to sets and updating the initial set to retain the corresponding set intersection.
const commonElements = function(arrays) {
if (arrays.length == 0)
return [];
const intersection = new Set(arrays[0]);
for (const array of arrays) {
const set = new Set(array);
for (x of intersection) {
if (!set.has(x))
intersection.delete(x);
}
}
return Array.from(intersection);
};
Calling this function on the sample arrays in the question:
commonElements([
[34, 23, 80, 93, 48],
[48, 29, 10, 79, 23],
[23, 89, 48, 20, 63]])
Returns:
[23, 48]

filter array of hashes with an array of keys ruby

arr = [
{
:id=>2,
:start=> "3:30",
break: 30,
num_attendees: 14
},
{
id: 3,
start: "3: 40",
break: 40,
num_attendees: 4
},
{
id: 4,
start: "4: 40",
break: 10,
num_attendees: 40
}
]
When I do the following
arr.map do |hash|
[ hash[:id], hash[:start] ]
end
returns
#=> [[2, "3:30"], [3, "3: 40"], [4, "4: 40"]]
Is there an elegant and efficient way of passing an array like return_keys = [:id, :start] and get the same above values rather than hard coding inside the array.map
Would you consider the following elegant and efficient?
arr.map { |h| h.values_at(:id, :start) }
#=> [[2, "3:30"], [3, "3: 40"], [4, "4: 40"]]
or
arr.map { |h| h.values_at(*return_keys) }
#=> [[2, "3:30"], [3, "3: 40"], [4, "4: 40"]]
I find the following really expressive
keys = [:id, :start]
arr.map {|hash| hash.slice(*keys).values}
The slice method returns a hash only with the keys passed as parameters (which are preceded by the * operator to convert an array into keyword arguments and avoid hardcoding). Then, the values method gets just the values out of the hash

Delete as many elements from the beginning of an array that match a value, until array reaches a specified size

I'm trying to modify an array by deleting values that match a unique ID, but then stop once the first 5 values of the array are valid (i.e. their IDs do not match the undesired ones). If the array has a count <= 5, then this suffices:
all_items = [{"id" => "id01"},{"id" => "id02"},{"id" => "id03"},{"id" => "id04"}]
exclude_ids = ["id01","id02"]
all_items.delete_if { |item| exclude_ids.include?(item["id"])}
and the desired output is [{"id" => "id03"},{"id" => "id04"}].
But in the case where the total count of the array is >= 5, I want to delete only as many of the first items as necessary until the first 5 elements (all_items[0..4]) are all valid within the set criterion, and then stop iterating. If I were to do this:
all_items = [{"id" => "id01"},{"id" => "id02"},{"id" => "id03"},{"id" => "id04"},{"id" => "id05"},{"id" => "id06"},{"id" => "id07"},{"id" => "id08"},{"id" => "id09"},{"id" => "id10"}]
exclude_ids = ["id01","id02","id07"]
all_items.delete_if { |item| exclude_ids.include?(item["id"])}
return all_items[0..4]
I do get the desired output, [{"id" => "id03"},{"id" => "id04"},{"id" => "id05"},{"id" => "id06"},{"id" => "id08"}]. But I want the delete_if to completely stop once it reaches the point where all_items[0..4] already contains 5 valid elements. In this instance, I would want it to break after {"id" => "id08"}, and not even check the remaining values. (If, however, while the delete_if is running, the total count dips below 5, then it should continue iterating over all remaining elements, as it would fall into the category of the first piece of code I posted above, where the count <= 5.)
I know there is a delete_if.with_index, but I'm not sure if it's appropriate in this context, especially since the index would be shifting as items are deleted.
To summarize my question: is there a way to delete as many first items from an array as is required until array[0..x] is populated by desired values, and then stop checking/deleting any remaining items once that count of x is reached?
termination_threshold = 5
all_items = (1..20).to_a
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
exclusions = [1,2,7]
all_items.reject! do |n|
break if termination_threshold.zero?
exclude = exclusions.include? n
termination_threshold -= 1 if exclude
exclude
end
#=> [3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
all_items
#=> [3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
The following could be used if only an array containing the first termination_threshold valid elements of all_items were desired:
all_items.each_with_object([]) do |e,arr|
arr << e unless exclusions.include?(e)
break arr if arr.size == termination_threshold
end
#=> [3, 4, 5, 6, 8]
If you delete from the original object you end up with all the items that had not been deleted. So, I gues it is better to move just the desired items to a new object:
all_items.each_with_object([]) { |item, ary| ary << item if !exclude_ids.include?(item["id"]) and ary.size < 5 }
#=> [{"id"=>"id03"}, {"id"=>"id04"}, {"id"=>"id05"}, {"id"=>"id06"}, {"id"=>"id08"}]
You can use Enumerator::Lazy to achieve what you want:
all_items = [{"id" => "id01"},{"id" => "id02"},{"id" => "id03"},{"id" => "id04"},{"id" => "id05"},{"id" => "id06"},{"id" => "id07"},{"id" => "id08"},{"id" => "id09"},{"id" => "id10"}]
exclude_ids = ["id01","id02","id07"]
all_items.lazy.reject {|item| exclude_ids.include?(item['id']) }.first(5)

Converting string into an array

I have a string:
key = "41521"
And I want to convert it into an array like this:
array = [41, 15, 52, 21]
I went about it like so:
array = []
array << key[0..1].to_i
array << key[1..2].to_i
array << key[2..3].to_i
array << key[3..4].to_i
What would be a better way?
key = "41521"
key.each_char.each_cons(2).map { |a| a.join.to_i }
#=> [41, 15, 52, 21]
or
key.gsub(/\d(?=(\d))/).with_object([]) { |s,a| a << (s<<$1).to_i }
#=> [41, 15, 52, 21]
or
a = []
e = key.each_char
#=> #<Enumerator: "41521":each_char>
loop { a << (e.next << e.peek).to_i }
a #=> [41, 15, 52, 21]
In #3 Enumerator#peek raises a StopInteration exception when the internal position of the enumerator is at the end (unless key is an empty string, in which case Enumerator#next raises the StopInteration exception). Kernel#loop handles the exception by breaking out of the loop.
key.gsub(/(?<=.)\d(?=.)/, '\&\&').scan(/\d{2}/).map(&:to_i)
# => [41, 15, 52, 21]
or
(0...key.length).map{|i| key[i, 2].to_i}
# => [41, 15, 52, 21, 1]
Not as short as some other answers, but for me, more easier to see the steps:
arr = key.chars.each_with_index
.reduce([]) {|s,(v,i)| s << (v + (key[i+1] || '')).to_i }
.select {|s| s.to_s.length > 1 }
# arr: [41, 15, 52, 21]
(0..(key.length-2)).map{|i| key.slice(i, 2)}

How to duplicate array within same array x times?

So, I have made function that return publicKey and I need to duplicate it x times for later use.
For example: publicKey: [76, 152, 93, 102, 145, 181] and I need to duplicate it 3 times, so the end result should be [76, 152, 93, 102, 145, 181, 76, 152, 93, 102, 145, 181, 76, 152, 93, 102, 145, 181].
I have tried using var list3 = publicKey*x, but as you can imagine, it didn't work..
fun getPublicKey(privateKey: ArrayList<BigInteger>,
birthDay: BigInteger,
primNumb: BigInteger): ArrayList<BigInteger> {
val inversMod = birthDay.modInverse(primNumb)
//println(inversMod)
val publicKey: ArrayList<BigInteger> = ArrayList()
for (keyValue in privateKey){
val pagaiduValue = (keyValue * inversMod).mod(primNumb)
//println("($keyValue * $inversMod) mod $primNumb = $pagaiduValue")
publicKey.add(pagaiduValue)
}
return publicKey
}
Here's a short and simple solution:
inline fun <T> Iterable<T>.times(count: Int) = (1..count).flatMap { this }
Can be used like this:
val numbers = listOf(1, 2, 3)
val result = numbers.times(5)
println(result) // [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
Perhaps the naming could use some work, times could also be assumed to have the effect of multiplying each element by a given number, repeat could be a better alternative. Also, you might wanna define it on Array<T> and the primitive array types (IntArray, etc) as well.

Resources