How can we convert list of list to map ? (Elixir) - data-structures

I have a list which consists of [A, B, C, D, E] and A has a list of values [1, 2, 3, 4, 5] similarly B has a list of values [1, 2, 3, 4, 5]
Date,SKU,Unit Price,Quantity,Total Price
2019-01-01,Death by Chocolate,180,5,900
2019-01-01,Cake Fudge,150,1,150
2019-01-01,Cake Fudge,150,1,150
2019-01-01,Cake Fudge,150,3,450
2019-01-01,Death by Chocolate,180,1,180
2019-01-01,Vanilla Double Scoop,80,3,240
2019-01-01,Butterscotch Single Scoop,60,5,300
2019-01-01,Vanilla Single Scoop,50,5,250
2019-01-01,Cake Fudge,150,5,750
Something like this but what I want is to create a map where the header is equal to values corresponding to it.
The expected output looks something like this:-
[%{date: '2019-01-01',SKU: 'Death by Chocolate', price: 50, quantity: 3},
%{date: '2019-01-01',SKU: 'Cake Fudge', price: 150, quantity: 3}]
I'm having a difficulty converting something like this.

For your specific use case a CSV parser will do what you're looking for, even if your file extension isn't .csv.
If you're just looking to use one list as keys for other lists, you can combine Enum.zip/2 with Map.new/1 to zip your header list with a row list and create a map (depending on file size you may want to work with streams instead of lists).
iex> [headers | rows] = do_some_parsing(text)
iex> headers
["Date", "SKU", "Unit Price", "Quantity", "Total Price"]
iex> rows
[["2019-01-01", "Death by Chocolate", 180, 5, 900],
["2019-01-01", "Cake Fudge", 150, 1, 150],
...]
iex> Enum.map(rows, fn row -> headers |> Enum.zip(row) |> Map.new() end)
[%{"Date" => "2019-01-01", "SKU" => "Death by Chocolate", "Unit Price" => 180, "Quantity" => 5, "Total Price" => 900},
%{"Date" => "2019-01-01", "SKU" => "Cake Fudge", "Unit Price" => 150, "Quantity" => 1, "Total Price" => 150},
...]

Related

How to calculate output of Keras UpSampling2D Layer?

I don't understand how the output of the Upsampling2d layer in Keras is calculated.
Let's take an example:
img_input = Input((2,2, 1))
out = UpSampling2D(size=2, interpolation="bilinear")(img_input)
model = Model(img_input, out, name='test')
input = np.array([[100, 200], [6, 8]]).reshape(1, 2, 2, 1)
model.predict(input).reshape(4, 4)
The result of this is:
array([[100. , 150. , 200. , 200. ],
[ 53. , 78.5, 104. , 104. ],
[ 6. , 7. , 8. , 8. ],
[ 6. , 7. , 8. , 8. ]], dtype=float32)
For me bilinear interpolation would get s.th. different. Let's take the 150 in the first row. For me this should be actually 100*(2/3) + 200*(1/3) = 133.33. What is different in this layer?
Thanks!
Given your input array, these are the steps to apply the bilinear upsampling of size=2:
# input array
[[100, 200],
[ 6, 8]]
# double the size and fill with existing values spreading them evenly.
# Important! the edges of the array are not filled:
[[100, _, 200, _],
[ _, _, _, _],
[ 6, _, 8, _],
[ _, _, _, _]]
# Start filling the empty spaces sequentially by applying this rule:
# Empty spaces surrounded by one or more filled values are filled with the
# arithmetic average of these values.
# We would fill the entire array in two steps:
# 1. The first step would look like this:
[[100, 150, 200, 200],
[ 53, _, 104, _],
[ 6, 7, 8, 8],
[ 6, _, 8, _]]
# 2. The second step would look like this:
[[100, 150, 200, 200],
[ 53,78.5, 104, 104],
[ 6, 7, 8, 8],
[ 6, 7, 8, 8]]
If you would rather get [100, 133, 166, 200] in the first row (and the rest of the array filled accordingly), you should produce an upsampling of size=3 and then remove the edges (res[1:5, 1:5]):
img_input = Input((2,2, 1))
out = UpSampling2D(size=3, interpolation="bilinear")(img_input)
model = Model(img_input, out, name='test')
input = np.array([[100, 200], [6, 8]]).reshape(1, 2, 2, 1)
model.predict(input).reshape(6, 6)[1:5, 1:5]
>> array([[100. , 133.33334 , 166.66667 , 200. ],
[ 68.666664 , 91.111115 , 113.55555 , 136. ],
[ 37.333324 , 48.888878 , 60.444427 , 71.999985 ],
[ 6. , 6.666667 , 7.3333335, 8. ]],
dtype=float32)

Delete duplicate entries in Ruby

What is the command for deleting duplicate elements in an array? This is my best try:
my_array.reject.with_string{s.clone}
If you want an array of unique values of my_array = [1, 2, 3, 3, 4], then do this:
my_array.uniq
# => [1, 2, 3, 4]
If your array contains objects with some field that you want to be unique, for example, :fname in:
my_array = [
{fname: "amanze", age: 28},
{fname: "ben", age: 13},
{fname: "ben", age: 4}
]
then you need to do this:
my_array.uniq { |obj| obj[:fname] }
# =>
# [
# {fname: "amanze", age: 28},
# {fname: "ben", age: 13}
# ]
Array#uniq is the best way to find out the uniq records, but as an alternate, you can use Array#&, which returns a new array containing the elements common to the two arrays, excluding any duplicates.
a = [1, 2, 3, 4, 5, 2, 2, 3, 4]
b = a & a
b #=> [1, 2, 3, 4, 5]

Ruby sort by multiple fields and multilple directions for different data types

I need to write a multi_sort method to sort an array of hash which accepts a hash as an argument, eg: { a_sort: 1, display_sort: 1 }. This hash is sort fields and sort direction. (1 means ascending, -1 means descending).
items = [ {name: 'Album 1', a_sort: 5, display_sort: 3},
{name: 'Album 2', a_sort: 1, display_sort: 5},
{name: 'Album 3', a_sort: 3, display_sort: 2},
{name: 'Album 5', a_sort: 1, display_sort: 8},
{name: 'Album 7', a_sort: 5, display_sort: 1},
{name: 'Album 7', a_sort: 5, display_sort: 6} ]
multi_sort(items, {a_sort: 1, display_sort: 1})
I can't figure it out after 3 hours. The expected output is the array that is sorted correctly.
[ {name: 'Album 2', a_sort: 1, display_sort: 5},
{name: 'Album 5', a_sort: 1, display_sort: 8},
{name: 'Album 3', a_sort: 3, display_sort: 2},
{name: 'Album 7', a_sort: 5, display_sort: 1}
{name: 'Album 1', a_sort: 5, display_sort: 3},
{name: 'Album 7', a_sort: 5, display_sort: 6} ]
Very interesting problem. I also think the sort_by method would be most helpful.
My solution (for numerical values only) works like this:
DIRECTION_MULTIPLIER = { asc: 1, desc: -1 }
def multi_sort(items, order)
items.sort_by do |item|
order.collect do |key, direction|
item[key]*DIRECTION_MULTIPLIER[direction]
end
end
end
# ... items ...
multi_sort(items, a_sort: :asc, display_sort: :desc)
The idea is to construct a list for each item passed by sort_by. This list consists out of all values for which a sort order was given. Hence, we use that Ruby knows that [1,2] is smaller than [1,3] but greater than [0,0].
An interesting part to note is that the last parameters for the function will be passed as one Hash and the order of these hash pairs will be maintained. This "ordered" behavior in Hashes is not necessarily true for all languages, but the Ruby documentation states: Hashes enumerate their values in the order that the corresponding keys were inserted.
-- Edit for more generality --
Since, chamnap asked for a more general solution which works with arbitrary data types and nil, here a more comprehensive solution which relies on the <=> operator:
require 'date'
DIRECTION_MULTIPLIER = { asc: 1, desc: -1 }
# Note: nil will be sorted towards the bottom (regardless if :asc or :desc)
def multi_sort(items, order)
items.sort do |this, that|
order.reduce(0) do |diff, order|
next diff if diff != 0 # this and that have differed at an earlier order entry
key, direction = order
# deal with nil cases
next 0 if this[key].nil? && that[key].nil?
next 1 if this[key].nil?
next -1 if that[key].nil?
# do the actual comparison
comparison = this[key] <=> that[key]
next comparison * DIRECTION_MULTIPLIER[direction]
end
end
end
I am using the sort method. The block gets called each time the sort function needs to compare to elements. The block shall return -1, 0 or 1 (smaller, equal or higher in the order) for the respective pair. Within this sort block I am going through the order hash which contains the key and the direction for a hash value in items. If we have found an earlier difference in order (e.g. the first key was higher) we just return that value. If the past comparisons came up with equal order, we use the <=> operator to compare the two elements passed to the sort block (and multiply the result it with -1 if we want descending order). The only annoying thing is to deal with nil values, which adds the three lines above the actual comparison.
And here my test code:
items = [ {n: 'ABC ', a: 1, b: Date.today+2},
{n: 'Huhu ', a: nil, b: Date.today-1},
{n: 'Man ', a: nil, b: Date.today},
{n: 'Woman', a: nil, b: Date.today},
{n: 'DEF ', a: 7, b: Date.today-1}]
multi_sort(items, b: :asc, a: :desc, n: :asc)
On a more general note: Since the logic for sorting becomes a little more complicated, I would wrap the data in actual objects with attributes. Then you could overwrite the <=> operator as seen here.
This only works with numeric values in the hash:
sort_by excepts an item to sort by, but since we want to sort by many items we should create a list.
Since we want to be able to decide directions we map each value in this list with either itself (1) or negative self (-1) causing the sort to be reversed.
items = [ {name: 'Album 1', a_sort: 5, display_sort: 3},
{name: 'Album 2', a_sort: 1, display_sort: 5},
{name: 'Album 3', a_sort: 3, display_sort: 2},
{name: 'Album 5', a_sort: 1, display_sort: 8},
{name: 'Album 7', a_sort: 5, display_sort: 1},
{name: 'Album 7', a_sort: 5, display_sort: 6} ]
def multi_sort(items, sort_directions)
items.sort_by do |row|
sort_directions.map{|key,val| val*row[key]}
end
end
puts multi_sort(items, {a_sort: 1, display_sort: -1}) # =>
#{:name=>"Album 5", :a_sort=>1, :display_sort=>8}
#{:name=>"Album 2", :a_sort=>1, :display_sort=>5}
#{:name=>"Album 3", :a_sort=>3, :display_sort=>2}
#{:name=>"Album 7", :a_sort=>5, :display_sort=>6}
#{:name=>"Album 1", :a_sort=>5, :display_sort=>3}
#{:name=>"Album 7", :a_sort=>5, :display_sort=>1}
Here is a version that uses sort and is a bit more complicated, can sort any data that can be sorted by the <=> operator:
def multi_sort(items, sort_directions)
items.sort do |row1,row2|
keys = sort_directions.map{|key,val| val*(row1[key]<=>row2[key])}
keys.find{|x|x!=0} || 0
end
end
puts multi_sort(items, {a_sort: -1, display_sort: 1}) # =>
#{:name=>"Album 1", :a_sort=>5, :display_sort=>"a"}
#{:name=>"Album 7", :a_sort=>5, :display_sort=>"a"}
#{:name=>"Album 7", :a_sort=>5, :display_sort=>"b"}
#{:name=>"Album 3", :a_sort=>3, :display_sort=>"b"}
#{:name=>"Album 5", :a_sort=>1, :display_sort=>"b"}
#{:name=>"Album 2", :a_sort=>1, :display_sort=>"v"}
Here is how it works. Sort takes two arguments (row1,row2), the two items that should be compared and expects a return value of -1, 0 or 1. When arg1>arg2 then -1, when arg2==arg1 then 0, when arg1
So, all we need to to is to figure this out. I take they keys and for each value in the hash I apply the <=> using the map function. I multiply the result with 1 or -1 to get the reverse effect. Then, I just got through the list of comparisons and pick the first non-zero value. If all columns are the same, the array will be full with zeros, and the sort will call them equal.
The most simple and basic solution to your problem(if I understand your problem correctly) is to use Enumerable#sort_by. For example, if you want to order elements by a_sort(it seems like it in your updated example) field in ascending order:
items.sort_by { |x| x[:a_sort] }
If you want to sort by two fields, you need some law by which sorting will be performed. The most simple random law(useless, but it'll work as an example) would be string concatenation, if we cast these values to string:
items.sort_by { |x| x[:a_sort].to_s + x[:display_sort].to_s }
If you want to sort by one field, then by another it sound(from your comment), you seem to want grouping. Something like this will be appropriate if you want to sort something less simple than two strings:
items.group_by { |x| x[:a_sort] }
.sort
.flat_map do |_, a|
a.sort_by { |x| x[:display_sort] }
end
It's not really efficient, but i think it's general enough to showcase my point.

Using Enumerable#zip on an Array of Arrays

I am trying to use Enumerable#zip on an array of arrays in order to group the elements of the first nested array with the corresponding elements of each subsequent nested array. This is my array:
roster = [["Number", "Name", "Position", "Points per Game"],
["12","Joe Schmo","Center",[14, 32, 7, 0, 23] ],
["9", "Ms. Buckets ", "Point Guard", [19, 0, 11, 22, 0] ],
["31", "Harvey Kay", "Shooting Guard", [0, 30, 16, 0, 25] ],
["7", "Sally Talls", "Power Forward", [18, 29, 26, 31, 19] ],
["22", "MK DiBoux", "Small Forward", [11, 0, 23, 17, 0] ]]
I want to group "Number" with "12", "9", "31", "7", and "22", and then do the same for "Name", "Position", etc. using zip. The following gives me the output I want:
roster[0].zip(roster[1], roster[2], roster[3], roster[4], roster[5])
How can I reformat this so that if I added players to my roster, they would be automatically included in the zip without me having to manually type in roster[6], roster[7], etc. I've tried using ranges in a number of ways but nothing seems to have worked yet.
First extract the head and tail of the list (header and rows, respectively) using a splat, then zip them together:
header, *rows = roster
header.zip(*rows)
This is the same as using transpose on the original roster:
header, *rows = roster
zipped = header.zip(*rows)
roster.transpose == zipped #=> true
:zip.to_proc[*roster]
a bit more flexible than transpose:
:zip.to_proc[*[(0..2), [:a, :b, :c]]] #=> [[0, :a], [1, :b], [2, :c]]
p roster.transpose()
.......................
roster[0].zip(*(roster[1..-1]))
Doesn't matter how many are in the roster array.

Ruby way of summing up dictionary values

I have something like this:
a = [{"group_id" => 1, "student_id" => 3, "candies" => 4},
{"group_id" => 2, "student_id" => 1, "candies" => 3},
{"group_id" => 1, "student_id" => 2, "candies" => 2},
{"group_id" => 3, "student_id" => 4, "candies" => 6},
{"group_id" => 1, "student_id" => 5, "candies" => 1},
{"group_id" => 3, "student_id" => 6, "candies" => 1},
{"group_id" => 4, "student_id" => 8, "candies" => 3}]
I have three groups of students and each student gets a certain number of candies. I wish to count the total number of candies in a group. For that, I need to know the students which belong to a certain group and accumulate their candy count. I can do it using loops and initializing counts to zero:
aa = a.group_by { |a| a["group_id"] }
# =>
{
1 => [
{"group_id"=>1, "student_id"=>3, "candies"=>4},
{"group_id"=>1, "student_id"=>2, "candies"=>2},
{"group_id"=>1, "student_id"=>5, "candies"=>1}
],
2 => [{"group_id"=>2, "student_id"=>1, "candies"=>3}],
3 => [
{"group_id"=>3, "student_id"=>4, "candies"=>6},
{"group_id"=>3, "student_id"=>6, "candies"=>1}
],
4 => [{"group_id"=>4, "student_id"=>8, "candies"=>3}]
}
But I'm not able to accumulate the values within the group_id. I wonder if there are any succinct ways of representing it. How do I sum the total number of candies that are present in a group?
The first your step (grouping) is correct. After that you can use the following:
a.group_by {|g| g['group_id']}.map do |g, students|
{group_id:g, candies:students.map {|st| st['candies']}.inject(&:+)}
end
map function is often used with collections instead of loops to make some operation on each element and return modified version of the collection.
Output:
[{:group_id=>1, :candies=>7},
{:group_id=>2, :candies=>3},
{:group_id=>3, :candies=>7},
{:group_id=>4, :candies=>3}]
Adding to #StasS answer, a more direct hash way to do (with a more cryptic code) is like this:
> Hash[a.group_by{|g| g['group_id']}.map{|g,s| [g, s.inject(0){|a,b| a + b["candies"]}]}]
=> {1=>7, 2=>3, 3=>7, 4=>3}
you can unfold the line like this:
groups = a.group_by{|g| g['group_id']}
id_candies_pairs = groups.map{|g,s| [g, s.inject(0){|a,b| a + b["candies"]}]}
id_candies_hash = Hash[id_candies_pairs]
return id_candies_hash
Riffing on the answer by #StasS, you can also just build a simpler looking hash like:
totals_by_group_id = {}
a.group_by {|g| g['group_id']}.map do |g, students|
totals_by_group_id[g] = students.map {|st| st['candies']}.inject(&:+)
end
The resulting totals_by_group_id hash is:
{1=>7, 2=>3, 3=>7, 4=>3}

Resources