Feature #8987
openmap/collect extension which handles arguments
Added by sowieso (So Wieso) about 11 years ago. Updated almost 7 years ago.
Description
Please consider extending map/collect by allowing additional arguments to be passed to proc, like:
A: [1,2,3,4].map :+, 4
and/or
B: [1,2,3,4].map 4, &:+
=> [5, 6, 7, 8]
Variant A is probably more readable. Variant B is more versatile (allows arbitrary arguments to be passed to block).
Files
mappi.rb (410 Bytes) mappi.rb | sample implementation in ruby (called mappi) | sowieso (So Wieso), 10/05/2013 11:02 PM |
Updated by sawa (Tsuyoshi Sawada) about 11 years ago
In case of commutative operations like +
, you can do it like this:
[1, 2, 3, 4].map(&4.method(:+))
# => [5, 6, 7, 8]
Updated by hsbt (Hiroshi SHIBATA) almost 11 years ago
- Target version changed from 2.1.0 to 2.2.0
Updated by ko1 (Koichi Sasada) almost 11 years ago
(2013/10/06 0:26), sawa (Tsuyoshi Sawada) wrote:
[1, 2, 3, 4].map(&4.method(:+)) # => [5, 6, 7, 8]
Interesting.
If we use λ (alias of lambda), it is more short.
module Kernel
alias λ lambda
end
p [1, 2, 3, 4].map(&4.method(:+)) #=> [5, 6, 7, 8]
p [1, 2, 3, 4].map(&λ{|x| 4+x}) #=> [5, 6, 7, 8]
If we define λ as the following definition, more short code.
module Kernel
def λ(a, sym)
lambda{|x| a.send(sym, x)}
end
end
p [1, 2, 3, 4].map(&λ(4, :+)) #=> [5, 6, 7, 8]
A bit shorter version.
module Kernel
def λ(expr)
eval("lambda{|x| #{expr} x}")
end
end
p [1, 2, 3, 4].map(&λ("4+")) #=> [5, 6, 7, 8]
If we have default parameter `_' (maybe matz doesn't like), we can make
more short code.
p [1, 2, 3, 4].map(&λ{4+_}) #=> [5, 6, 7, 8]
Summary:
p [1, 2, 3, 4].map(&4.method(:+)) #=> [5, 6, 7, 8]
p [1, 2, 3, 4].map(&λ{|x| 4+x}) #=> [5, 6, 7, 8]
p [1, 2, 3, 4].map(&λ(4, :+)) #=> [5, 6, 7, 8]
p [1, 2, 3, 4].map(&λ("4+")) #=> [5, 6, 7, 8]
p [1, 2, 3, 4].map(&λ{4+_}) #=> [5, 6, 7, 8] (doesn't run)
--
// SASADA Koichi at atdot dot net
Updated by phluid61 (Matthew Kerwin) almost 11 years ago
On 31 January 2014 15:48, SASADA Koichi ko1@atdot.net wrote:
p [1, 2, 3, 4].map(&4.method(:+)) #=> [5, 6, 7, 8] p [1, 2, 3, 4].map(&λ{|x| 4+x}) #=> [5, 6, 7, 8] p [1, 2, 3, 4].map(&λ(4, :+)) #=> [5, 6, 7, 8] p [1, 2, 3, 4].map(&λ("4+")) #=> [5, 6, 7, 8] p [1, 2, 3, 4].map(&λ{4+_}) #=> [5, 6, 7, 8] (doesn't run)
Are any of these actually better than:
p [1, 2, 3, 4].map{|x| 4+x }
?
--
Matthew Kerwin
http://matthew.kerwin.net.au/
Updated by ko1 (Koichi Sasada) almost 11 years ago
Matthew Kerwin wrote:
Are any of these actually better than:
p [1, 2, 3, 4].map{|x| 4+x }
?
LOL
Updated by sowieso (So Wieso) almost 11 years ago
Matthew Kerwin wrote:
On 31 January 2014 15:48, SASADA Koichi ko1@atdot.net wrote:
p [1, 2, 3, 4].map(&4.method(:+)) #=> [5, 6, 7, 8] p [1, 2, 3, 4].map(&λ{|x| 4+x}) #=> [5, 6, 7, 8] p [1, 2, 3, 4].map(&λ(4, :+)) #=> [5, 6, 7, 8] p [1, 2, 3, 4].map(&λ("4+")) #=> [5, 6, 7, 8] p [1, 2, 3, 4].map(&λ{4+_}) #=> [5, 6, 7, 8] (doesn't run)
Are any of these actually better than:
p [1, 2, 3, 4].map{|x| 4+x }
?
--
Matthew Kerwin
http://matthew.kerwin.net.au/
Actually I believe the most readable form would be
p [1,2,3,4].map{ 4 + _ } # when there is no |…|, set block params to _
Many blocks in realworld-code are so easy, that it is really a barrier to have to think about a name, and therefore one uses often non-verbose names like you used x
. Where is the point in being forced to think of a name, when you don't set the name to something meaningful. I guess this was the idea why the to_proc
convention was introduced. The problem with it is, that it is really limiting because you cannot use parameters (and the presence of a parameter doesn't necessarily make problems so complex to justify a name).
Updated by mame (Yusuke Endoh) almost 11 years ago
Just joke.
p [0,1,2,3].dmap + 1 #=> [1, 2, 3, 4]
# %w(foo bar baz).map {|x| x.upcase.concat("!") }
p %w(foo bar baz).map_do.upcase.concat("!").end
# => ["FOO!", "BAR!", "BAZ!"]
Source:
class DelegateMap < BasicObject
def initialize(enum)
@enum = enum
end
def method_missing(mhd, *args, &blk)
@enum.map {|elem| elem.__send__(mhd, *args, &blk) }
end
end
class CascadingDelegateMap < BasicObject
def initialize(enum)
@enum = enum
end
def method_missing(mhd, *args)
::CascadingDelegateMap.new(@enum.map {|elem| elem.send(mhd, *args) })
end
def end
@enum
end
end
module Enumerable
def dmap
DelegateMap.new(self)
end
def map_do
CascadingDelegateMap.new(self)
end
end
--
Yusuke Endoh mame@tsg.ne.jp
Updated by phluid61 (Matthew Kerwin) almost 11 years ago
On Jan 31, 2014 6:20 PM, sowieso@dukun.de wrote:
Actually I believe the most readable form would be
p [1,2,3,4].map{ 4 + _ } # when there is no |...|, set block params to _
Many blocks in realworld-code are so easy, that it is really a barrier to
have to think about a name, and therefore one uses often non-verbose names
like you used x. Where is the point in being forced to think of a name,
when you don't set the name to something meaningful. I guess this was the
idea why the to_proc convention was introduced. The problem with it is,
that it is really limiting because you cannot use parameters (and the
presence of a parameter doesn't necessarily make problems so complex to
justify a name).
I guess you can solve it by syntax or by convention. I've, personally,
never had a pause when calling it 'x' or 'item', depending on the context.
You could also develop the convention of: arr.map{|_| ... }
My only problem with magic variables is that I can never remember when they
get (re)assigned. It's particularly annoying in perl, because those guys
never assign a variable when $_ will suffice.
Matthew Kerwin
Updated by sawa (Tsuyoshi Sawada) almost 11 years ago
Probably, it makes more sense to extend the syntax of Symbol#to_proc
. The conventional Symbol#to_proc
does not take an argument:
:foo.to_proc # => ->(x){x.foo}
My proposal is to let it take optional arguments that would be passed to the method within the created proc:
:foo.to_proc(y) # => ->(x){x.foo(y)}
So that
:+.to_proc(4) # => ->(x){x + 4}
[1, 2, 3, 4].map(&:+.to_proc(4)) # => [5, 6, 7, 8]
Not sure if any better than writing the original, but looks consistent.
Or, maybe we can use the method name Symbol#call
, which is aliased to short forms, so that we can do:
:+.call(4) # => ->(x){x + 4}
:+.(4) # => ->(x){x + 4}
[1, 2, 3, 4].map(&:+.(4)) # => [5, 6, 7, 8]
Updated by henry.maddocks (Henry Maddocks) almost 11 years ago
Tsuyoshi Sawada wrote:
Probably, it makes more sense to extend the syntax of
Symbol#to_proc
. The conventionalSymbol#to_proc
does not take an argument:
+1
Updated by nobu (Nobuyoshi Nakada) over 10 years ago
- Related to Feature #4146: Improvement of Symbol and Proc added
Updated by nobu (Nobuyoshi Nakada) over 10 years ago
- Description updated (diff)
Updated by naruse (Yui NARUSE) almost 7 years ago
- Target version deleted (
2.2.0)