Cannot get [{"foo"}, {"bar"}, {}, {}] |> filter empty to work - prelude.ls

This works:
[1 to 10] |> filter (> 4) |> console.log #[ 5, 6, 7, 8, 9, 10 ]
This works:
empty {} #true
but this doesn't:
[{"foo"}, {"bar"}, {}, {}] |> filter empty |> console.log # [ { foo: 'foo' }, { bar: 'bar' }, {}, {} ]
[{"foo"}, {"bar"}, {}, {}] |> map (-> console.log (empty it) ) #true true true true
Is this a problem with empty?
Any help will be appreciated.

My current workaround is to implement my own empty:
empty = (obj)->
Object.keys(obj).length is 0

You need to use the appropriate empty function for the type of input you are using, in this case, use Obj.empty. The empty you are using comes from List.empty. Using that on an object should probably be an error instead of what currently happens.
[{"foo"}, {"bar"}, {}, {}] |> filter Obj.empty

Related

Efficient way to subtract arrays and get index of resulting subarray

Lets say I have the following arrays:
arr1 = [
['a', 'b'],
['c', 'd'],
['e', 'f']
]
arr2 = [
['g', 'h'],
['i', 'k'],
['a', 'b']
]
I want to find the elements in arr1 that do not exist in arr2 and the index of the elements in arr1
I can do this with the following but this isn't very efficient and is not a pretty solution. There can also be many elements in the arrays so this does not scale. Is there a better way to do this?
diff = arr1 - arr2
diff_with_index = diff.map { |x| { index: arr1.index(x), values: x } }
print diff_with_index
# [{:index=>1, :values=>["c", "d"]}, {:index=>2, :values=>["e", "f"]}]
When you have to do multiple include? checks, the most efficient way is to turn one of the lists into a set or hash beforehand, so you can have O(1) lookup time, so something like this:
require 'set'
arr2_set = Set.new(arr2)
arr1.each_index.select { |idx| !arr2_set.include?(arr1[idx]) }
Here is one way.
i1 = (0..arr1.size-1).to_a
#=> [0, 1, 2]
h1 = arr1.zip(i1).to_h
#=> {["a", "b"]=>0, ["c", "d"]=>1, ["e", "f"]=>2}
i1 - arr2.map { |a| h1[a] }
#=> [1, 2]
Note that
arr2.map { |a| h1[a] }
#=> [nil, nil, 0]

Reduce array elements into nested class instantiation

Given I have the following array:
operations = [
[
:do_this,
["a"]
],
[
:do_that,
["b", "c"]
],
[
:then_this,
["b"]
]
]
How do I transform above so it looks like:
DoThisOperation.new(DoThatOperation.new(ThenThisOperation.new('b'), 'b' , 'c'), 'a')
This is as far as I've gotten:
require 'active_support/inflector'
class DoThisOperation
def initialize(successor = nil, a)
end
end
class DoThatOperation
def initialize(successor = nil, b, c)
end
end
class ThenThisOperation
def initialize(successor = nil, b)
end
end
operations = [
[
:do_this,
["a"]
],x
[
:do_that,
["b", "c"]
],
[
:then_this,
["b"]
]
]
operations.reverse.reduce do |result, element|
klass_name = element[0].to_s.camelize
args = element[1]
"#{klass_name}Operation".constantize.new(result, *args)
end
Is reduce/inject the right way to go about this? If so, what should I be doing above?
Is reduce/inject the right way to go about this?
Yes, but you need to pass an initial value to reduce, e.g. nil. Otherwise, the first element (in your case the last element) will be used as the initial value without being converted.
This would work:
operations.reverse.reduce(nil) do |result, element|
klass_name = element[0].to_s.camelize
args = element[1]
"#{klass_name}Operation".constantize.new(result, *args)
end
You can further simplify it by using array decomposition:
operations.reverse.reduce(nil) do |result, (name, args)|
klass_name = name.to_s.camelize
"#{klass_name}Operation".constantize.new(result, *args)
end
Or even:
operations.reverse.reduce(nil) do |result, (name, args)|
"#{name}_operation".camelize.constantize.new(result, *args)
end

Can someone please explain use of each_with_index, reduce, select chained in the code along with OR (||)?

Can someone explain this code to me? What does the || syntax mean and how does it work?
array = [1, 2, 3, 4, 5, 3, 6, 7, 2, 8, 1, 9]
array.each_with_index.reduce({}) { |hash, (item, index)|
hash[item] = (hash[item] || []) << index
hash
}.select{ |key, value| value.size > 1 }
I'd rewrite it this way
array.each_with_index.reduce(Hash.new { Array.new }) do |hash, (item, index)|
hash.merge(item => hash[item] << index)
end.select { |_, indexes| indexes.size > 1 }
We use each_with_index because we want to access the index while looping the array. You can see it later next to item as a parameter in the reduce's block.
reduce permits us to "transform" a collection in something else. In our case we want to construct an hash out of an array.
In the reduce's block we add the current index to the key value pair for the current item. I used merge to do it in just one expression (update the hash and using it as an expression to return).
In the end, we keep just the key value pairs whose values (and those are arrays) have more than one elements. Note that we don't care about keys here so I called the key parameter _.
array = [1, 2, 3, 4, 5, 3, 6, 7, 2, 8, 1, 9]
array.each_with_index.reduce({}) do |hash, (item, index)|
hash[item] = (hash[item] || []) << index
hash
end.select do |key, value|
value.size > 1
end
First of all cleaner way of writing Enumerators single line are enclosed with {} and multiline with do; end.
array.each_with_index.reduce({}) do |hash, (item, index)|
# hash[item] gets either itself and if itself is nil it gets an empty
# array assigned and additionally the index gets added to this array
hash[item] = (hash[item] || []) << index
# return the hash for the reduce enumerator
hash
end
In this part you iterate over the array and pass in the initial empty hash with .reduce({}). The hash then gets transformed and returned in L3 in the "loop" and passed into the next iteration of the reduce. Your result then is the build up hash which then immediately get enumerated with select where only key value pairs get returned that have a value size larger than 1.
Best would be to readup on Enumerators#reduce and how the objects are passed into the "loop".
hash[item] is nil at first. nil || [] => [], so hash[item] become array. << push an item into array.
hope this can help you understand how hash store the value
require "pp"
hash = {}
pp hash[1] # => nil
pp hash[1] || [] # => []
pp (hash[1] || []) << 1 # => [1]
pp hash[1] # => nil
hash[1] = (hash[1] || []) << 1
pp hash[1] # => [1]

Group by boolean value but change key in ruby on rails

I'm sorting an array by the before attribute which is a boolean, this works but I'd rather not use true and false as the hash values and use 'before' when true and 'after' when before equals false
a.each { |x| arr << x.answers.group_by(&:before) unless x.answers == nil }
Is there a simple way to do this?
i.e instead of having true: [], false: []
I'd prefer to have before: [], after: []
Sure like this
x.answers.group_by {|e| e.before ? :before : :after}
this will create a Hash of {before: [],after:[]}
eg.
a = [1,2,3,4,5,6,7]
a.group_by {|n| n.odd? ? :odd : :even}
#=> {odd: [1, 3, 5, 7], even: [2, 4, 6]}
#group_by works on the return response from the block so true and false become keys but you can replace the response with anything you like and these will act as the keys instead. This means you could have more than 2 returns e.g.
a = [1,2,3,4,5,6,7]
a.group_by {|n| n == 2 ? :two : n == 3 ? :three : n.odd? ? :odd : :even}
#=> {:odd=>[1, 5, 7], :two=>[2], :three=>[3], :even=>[4, 6]}
I used ternary operators to save space I would not recommend nesting them this deep as it takes away from readability this was just an example.

How to rotate by 90° an Array with ActiveRecord objects

I have got
#my_objects = [ #<MyObject id: 1, title: "Blah1">,
#<MyObject id: 2, title: "Blah2">,
#<MyObject id: 3, title: "Blah3">,
#<MyObject id: 4, title: "Blah4"> ]
I need to turn it into:
#my_objects = { :id => [ 1, 2, 3, 4],
:title => [ "Blah1" ... ] }
Is there built in method or some standart approach?
I can imagine only this
#my_objects.inject({}){ |h, c| c.attributes.each{ |k,v| h[k] ||= []; h[k] << v }; h }
This question was born while I was thinking on this particular question
First, use Enumerable#map (something like #o.map { |e| [e.id, e.title] }) to get the ActiveRecord array into a simplified pure Ruby object that looks like this:
a = [[1, "Blah1"], [2, "Blah2"], [3, "Blah3"], [4, "Blah4"]]
Then:
a.transpose.zip([:id, :title]).inject({}) { |m, (v,k)| m[k] = v; m }
Alternate solution: It might be less tricky and easier to read if instead you just did something prosaic like:
i, t = a.transpose
{ :id => i, :title => t }
Either way you get:
=> {:title=>["Blah1", "Blah2", "Blah3", "Blah4"], :id=>[1, 2, 3, 4]}
Update: Tokland has a refinement that's worth citing:
Hash[[:id, :title].zip(a.transpose)]
You're on the right track there, there's no custom method for this sort of pivot, and it should work, but remember that ActiveRecord attribute keys are strings:
#my_objects.inject({ }) { |h, c| c.attributes.each { |k,v| (h[k.to_sym] ||= [ ]) << v }; h }
You can use the (x ||= [ ]) << y pattern to simplify that a bit if you're not too concerned with it being super readable to a novice.
Functional approach (no eachs!):
pairs = #my_objects.map { |obj| obj.attributes.to_a }.flatten(1)
Hash[pairs.group_by(&:first).map { |k, vs| [k, vs.map(&:second)] }]
#=> {:title=>["Blah1", "Blah2", "Blah3", "Blah4"], :id=>[1, 2, 3, 4]}
As usual, Facets allows to write nicer code; in this case Enumerable#map_by would avoid using the ugly and convoluted pattern group_by+map+map:
#my_objects.map { |obj| obj.attributes.to_a }.flatten(1).map_by { |k, v| [k, v] }
#=> {:title=>["Blah1", "Blah2", "Blah3", "Blah4"], :id=>[1, 2, 3, 4]}

Resources