Sort Array based on other Sorted Array - sorting

I have two arrays of the same size and I sort the second one. How can I array the first one to match?
Basic example (imagine replacing Ints with Strings):
var array1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
var array2 = [5, 2, 3, 4, 5, 6, 8, 5, 4, 5, 1]
array2.sort = ({ $0 > $1})
Result:
array2 is now [8, 6, 5, 5, 5, 5, 4, 4, 3, 2, 1]
How to sort array1's index value to match array2?
array1 should now be [6, 5, 0, 4, 7, 9, 3, 8, 2, 1, 0]

Zip2, sorted and map
array1 = map(sorted(Zip2(array1, array2), {$0.1 > $1.1}), { $0.0 })
Combining filter
var array1 = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]
var array2 = [5, 2, 3, 4, 5, 6, 8, 5, 4, 5, 1]
func isEven(x:Int) -> Bool {
return x % 2 == 0
}
let result = map(sorted(filter(Zip2(array1, array2), { isEven($0.1) }), {$0.1 > $1.1}), { $0.0 })
// -> ["6", "5", "3", "8", "1"]
As you can see, the line is too complex, you might want to Array method chain syntax:
let result2 = Array(Zip2(array1, array2))
.filter({ isEven($0.1) })
.sorted({ $0.1 > $1.1 })
.map({ $0.0 })
Anyway, if your array2 is [PFObject], you can implement the function something like:
func isOpen(restaurant: PFObject, forTime time: String, onDay day: Int) -> Bool {
// return `true` if the restaurant is open, `false` otherwise
}

Related

I'm trying to use elasticsearch aggregation generate array having sum of each element of array

I have documents that look like:
{
"arr": [5, 4, 3, 2, 1],
"name": "test"
}
{
"arr": [4, 3, 2, 1, 0],
"name": "test"
}
{
"arr": [1, 0, 0, 0, 0],
"name": "test"
}
I want to use an aggregation (or some other es method) to return:
{
"arr": [10, 7, 5, 3, 1]
}
Elasticsearch doesn't "properly" store lists; in your case internal representation of such field would be arr = 5 AND arr = 4 AND .... Though if all docs have 5 items (or less) you can do something like:
{
"arr": [5, 4, 3, 2, 1],
"arr_0": 5,
"arr_1": 4,
"arr_2": 3,
"arr_3": 2,
"arr_4": 1,
"name": "test"
}
and then 5 sum aggregations over arr_0 ... arr_4.
If there is no limit on the array length, you'll have to compute in your app I'm afraid.

How to find the list of pairs in an array using ruby?

Input:
a = [4, 5, 5, 5, 6, 6, 4, 1, 4, 4, 3, 6, 6, 3, 6, 1, 4, 5, 5, 5]
How to list out no of pairs in an array.
Output:
9
Description
#no 1(1 pair)
#no 3(1 pair)
#no 4(2 pairs)
#no 5(3 pairs)
#no 6(2 pairs)
#so total 9 pairs
Here is another option:
a.group_by(&:itself).transform_values{ |v| v.size / 2 }.values.sum
#=> 9
How it works.
First group the elements by value:
a.group_by(&:itself) #=> {4=>[4, 4, 4, 4, 4], 5=>[5, 5, 5, 5, 5, 5], 6=>[6, 6, 6, 6, 6], 1=>[1, 1], 3=>[3, 3]}
Then transforming the keys to the pair count:
a.group_by(&:itself).transform_values{ |v| v.size / 2 } #=> {4=>2, 5=>3, 6=>2, 1=>1, 3=>1}
So, get the values of the hash:
a.group_by(&:itself).transform_values{ |v| v.size / 2 }.values #=> [2, 3, 2, 1, 1]
Finally, sum the values, which is the first line of code posted above.
arr = [4, 5, 5, 5, 6, 6, 4, 1, 4, 4, 3, 6, 6, 3, 6, 1, 4, 5, 5, 5]
hash = Hash.new(0)
arr.each { |e| hash[e] += 1 }
hash.values.reduce(0) { |s, n| s += n / 2 } // => 9
Since from what I can gather you are basically removing integers the moment they got paired once so technically it's just an integer division by two.
[1] How to count identical string elements in a Ruby array
[2] Reduce Hash Values
I have done like this, It works
b = []
a.uniq.each { |i| b.push(a.count(i)/2)}
b.sum

How to find highest char value in ruby?

Suppose I'm given a string "Nas". I want to select the char which has the highest integer value. How can I do this in Ruby?
My implementation involved creating a hash with the numerical value for each char:
alpha = {}
('a'...'z').zip(1. .26).each do |x| alpha[x[0]] = x[1] end
And then I'd loop through my word like so:
word.each_char do |c |
puts c
end
I have defined a method which takes two parameters, the first param is an array which specifies the "importance of a char", and second param takes a word:
def designer_pdf(h, word)
alpha = {}
('a'...'z').zip(1..26).each do |x|
alpha[x[0]] = x[1]
end
word.each_char do |c|
puts c
end
end
designer_pdf (
[1, 3, 1, 3, 1, 4, 1, 3, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5],
'abc'
)
The goal is two return the highest value from the h array based on the character from word.
For example, word: 'abc':
a = 1
b = 3
c = 1
So return 3 because b is highest.
You can do this
For zep string
p [*'a'..'z'].zip([1, 3, 1, 3, 1, 4, 1, 3, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5])
.select{|x|("zeb".chars).include?x[0]}.max_by{|x|x[1]}
output
["z", 5]
You can pass any priority array and any word as arguments:
def designer_pdf(h, word)
alpha = Hash[('a'..'z').zip(h)]
# if you want only character from word with highest priority
character = word.chars.max_by{|e| alpha[e]}
# if you want only highest char value
value = alpha[character]
# if you want both character and value
[character, value]
end
> designer_pdf([1, 3, 1, 3, 1, 4, 1, 3, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5], "abc")
#=> ["b", 3]
> designer_pdf([1, 3, 1, 3, 1, 4, 1, 3, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5], "zeb")
#=> ["z", 5]
There is no need to construct a hash.
def largest_mapped_value(word, values)
base = 'a'.ord
values[word.each_char.max_by { |c| values[c.ord-base] }.ord-base]
end
# a b c d e f g h i j k l m n o p q r s t
values = [1, 3, 1, 3, 1, 4, 1, 3, 2, 5, 6, 5, 5, 7, 5, 5, 5, 5, 5, 1,
5, 5, 5, 5, 5, 5]
# u v w x y z
%w| cat kite zebra fined a |.each { |word|
puts "#{word}: #{largest_mapped_value(word, values)}" }
cat: 1
kite: 6
zebra: 5
fined: 7
a: 1
A variant is the following.
word = "fined"
base = 'a'.ord
#=> 97
word.each_char.map { |c| values[c.ord-base] }.max
#=> 7

Why am I getting a No Method Error?

I'm new to ruby and am still having trouble parsing error messages. My method takes a string in this form:
"8, 2, 1, 6; 3, 1, 3, 2; 6, 4, 2, 7; 7, 3, 2, 4"
My goal is to split each set (offset by ;) into a subarray of an array and convert each value in the subarrays to an integer. Then, I need to print the second value in each subarray. I am getting stuck on the last part. Here is the code:
#input = "8, 2, 1, 6; 3, 1, 3, 2; 6, 4, 2, 7; 7, 3, 2, 4"
#array = []
def splitter
#input.gsub!(/\s+/, '')
#array = #input.split(';').map { |group| group.split(',') }
#array.map! { |subarray| subarray.map! {|v| v.to_i} }
#array.each { |e| print e(1) }
puts ''
end
splitter
and here is the error message:
`block in splitter': undefined method `e' for main:Object (NoMethodError)
I'm wondering if I'm not using the right form for an array of arrays.
str = "8, 2, 1, 6; 3, 1, 3, 2; 6, 4, 2, 7; 7, 3, 2, 4"
str.split(';').map { |e| e.split(',').map(&:to_i) }
#⇒ [[8, 2, 1, 6], [3, 1, 3, 2], [6, 4, 2, 7], [7, 3, 2, 4]]

How to insert a new element in between all elements of a Ruby array?

I have an Array and want to insert a new element in between all elements, someway like the join method. For example, I have
[1, [], "333"]
and what I need is
[1, {}, [], {}, "333"]
Note a new empty hash was inserted in between all elements.
Edit:
Currently what I have is:
irb(main):028:0> a = [1, [], "333"]
=> [1, [], "333"]
irb(main):029:0> a = a.inject([]){|x, y| x << y; x << {}; x}
=> [1, {}, [], {}, "333", {}]
irb(main):030:0> a.pop
=> {}
irb(main):031:0> a
=> [1, {}, [], {}, "333"]
irb(main):032:0>
I want to know the best way.
[1, 2, 3].flat_map { |x| [x, :a] }[0...-1]
#=> [1, :a, 2, :a, 3]
FYI, that function is called intersperse (at least in Haskell).
[Update] If you want to avoid the slice (that created a copy of the array):
[1, 2, 3].flat_map { |x| [x, :a] }.tap(&:pop)
#=> [1, :a, 2, :a, 3]
Another similar solution uses #product :
[1, 2, 3].product([{}]).flatten(1)[0...-1]
# => [ 1, {}, 2, {}, 3 ]
a = [1,2,3]
h, *t = a
r = [h]
t.each do |e|
r.push({}, e)
end
r #=> [1, {}, 2, {}, 3]
You could do something like:
a = [1, [], "333"]
new_a = a.collect {|e| [e, {}]}.flatten(1)
=> [1, {}, [], {}, "333", {}]
You need to do .flatten(1) because it will flatten your blank array without it.
Or as #David Grayson says in the comment, you can do a flat_map which will do the same thing.
a.flat_map {|e| [e, {}]}
=> [1, {}, [], {}, "333", {}]
#tokland has the correct answer if the last {} is not necessary. You return a slice from 0 to length - 1 or [0..-1].
Another one that's similar to Tokland's:
xs.inject([]){|x,y| x << y << {}}[0...-1]
One approach is to zip another array of desired elements and then flatten it with depth = 1:
> arr = [1, [], "333"]
> element = {}
> interspersed = arr.zip([element] * (arr.size - 1)).flatten(1).compact
> # [1, {}, [], {}, "333" ]
You can extend Array to make this behavior more accessible.
class Array
def intersperse(elem)
self.zip([elem] * (self.size - 1)).flatten(1).compact
end
end
e.g.,
[43] pry(main)> [1,2,3].intersperse('a')
=> [1, "a", 2, "a", 3]
[1, 2, 3, 4, 5].inject { |memo, el| Array(memo) << {} << el }
#=> [1, {}, 2, {}, 3, {}, 4, {}, 5]
inject will use the first element to start with, so you don't need to mess with indices.
irb(main):054:0* [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(1).flat_map {|e| e << "XXX"}[0...-1]
=> [1, "XXX", 2, "XXX", 3, "XXX", 4, "XXX", 5, "XXX", 6, "XXX", 7, "XXX", 8, "XXX", 9]
irb(main):055:0> [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(2).flat_map {|e| e << "XXX"}[0...-1]
=> [1, 2, "XXX", 3, 4, "XXX", 5, 6, "XXX", 7, 8, "XXX", 9]
irb(main):056:0> [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(3).flat_map {|e| e << "XXX"}[0...-1]
=> [1, 2, 3, "XXX", 4, 5, 6, "XXX", 7, 8, 9]
irb(main):057:0> [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(4).flat_map {|e| e << "XXX"}[0...-1]
=> [1, 2, 3, 4, "XXX", 5, 6, 7, 8, "XXX", 9]
irb(main):058:0> [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(5).flat_map {|e| e << "XXX"}[0...-1]
=> [1, 2, 3, 4, 5, "XXX", 6, 7, 8, 9]
irb(main):059:0> [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(6).flat_map {|e| e << "XXX"}[0...-1]
=> [1, 2, 3, 4, 5, 6, "XXX", 7, 8, 9]
irb(main):060:0> [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(7).flat_map {|e| e << "XXX"}[0...-1]
=> [1, 2, 3, 4, 5, 6, 7, "XXX", 8, 9]
irb(main):061:0> [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(8).flat_map {|e| e << "XXX"}[0...-1]
=> [1, 2, 3, 4, 5, 6, 7, 8, "XXX", 9]
irb(main):062:0> [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(9).flat_map {|e| e << "XXX"}[0...-1]
=> [1, 2, 3, 4, 5, 6, 7, 8, 9]
irb(main):063:0>

Resources