ruby,inject , Map with accumulator on an array

## Question:

Tag: ruby,inject

I'm looking to create a method for Enumerable that does map and inject at the same time. For example, calling it map_with_accumulator,

[1,2,3,4].map_with_accumulator(:+)
# => [1, 3, 6, 10]


or for strings

['a','b','c','d'].map_with_accumulator {|acc,el| acc + '_' + el}
# => ['a','a_b','a_b_c','a_b_c_d']


I fail to get a solution working. I think I can do it with reduce. I was working down the path of something like:

arr.reduce([]) {|acc,e| ..... }


with the initial value being an empty array, but I couldn't get it correct.

This operation is called scan or prefix_sum, but unfortunately, there is no implementation in the Ruby core library or standard libraries.

However, your intuition is correct: you can implement it using Enumerable#inject. (Actually, Enumerable#inject is general, every iteration operation can be implemented using inject!)

module Enumerable
def scan(initial)
inject([initial]) {|acc, el| acc << yield(acc.last, el) }
end
end

[1,2,3,4].scan(0, &:+)
# => [0, 1, 3, 6, 10]

%w[a b c d].scan('') {|acc, el| acc + '_' + el }
# => ["", "_a", "_a_b", "_a_b_c", "_a_b_c_d"]


Ideally, the behavior should match that of inject with its 4 overloads (in which case it would give you the results you specified), but unfortunately, implementing those overloads in Ruby, without privileged access to the VM internals (in particular, the arguments at the send site) is a major pain in the rear section.

It goes something like this:

module Enumerable
# Trying to match the signature of inject without access to the VM internals
# is a PITA :-(
def scan(initial=(initial_not_given = true; first), meth=nil)
raise ArgumentError, 'You can pass either a block or a method, not both.' if block_given? && meth
return enum_for(__method__) if initial_not_given && !meth && !block_given?
return enum_for(__method__, initial) unless initial.is_a?(Symbol) || meth || block_given?
meth, initial, initial_not_given = initial, first, true unless initial_not_given || meth || block_given?
raise ArgumentError, "Method #{meth.inspect} is not a Symbol." unless meth.is_a?(Symbol) || block_given?

this = if initial_not_given then drop(1) else self end

return this.inject([initial]) {|acc, el| acc << acc.last.__send__(meth, el) } unless block_given?
this.inject([initial]) {|acc, el| acc << yield(acc.last, el) }
end
end

[1,2,3,4].scan(:+)
# => [1, 3, 6, 10]

%w[a b c d].scan {|acc, el| acc + '_' + el }
# => ["a", "a_b", "a_b_c", "a_b_c_d"]


As you can see, the implementation in terms of inject itself is rather elegant, the ugliness is solely due to implementing overloading in a language without overloading.

# Related:

## How to handle backslash “\” escape characters in q string and heredocument

ruby
Ruby Newbie here. I do not understand why Ruby looks inside %q and escapes the \. I am using Ruby to generate Latex code. I need to generate \\\hline which is used in Latex for table making. I found \\\hline as input generated \hline even though the string was inside...

## How could I padding spaces to a fix length

ruby
I need all strings' length with 5 Original [477, 4770,] Expected ["477 ", "4770 "] How could I do it with Ruby ?...

## Rails less url path change

ruby-on-rails,ruby,url,path,less
Developing a Rails application with the less-rails gem I found something unusual : // app/assets/common/css/desktop/typo.less @font-face{ font-family:'SomeFont'; src:url("fonts/db92e416-da16-4ae2-a4c9-378dc24b7952.eot?#iefix"); // ... } The requested font is app/assets/common/css/fonts/db92e416-da16-4ae2-a4c9-378dc24b7952.eot This font is compiled with less and the results is : @font-face { font-family: 'SomeFont'; src: url("desktop/fonts/db92e416-da16-4ae2-a4c9-378dc24b7952.eot?#iefix"); //... } Do you know why is...

ruby

## Call method to generate arguments in ruby works in 1.8.7 but not 1.9.3

ruby-on-rails,ruby,ruby-1.9.3
This is something that I had working in ruby 1.8.7, but no longer works in 1.9.3, and I am not sure what changes make this fail. Previously, I had something like this myFunction(submitArgs()) where submitArgs was a helper method that could be called with some options def submitArgs(args={}) #Some logic/manipulations...

## Seeding fails validation for nested tables (validates_presence_of)

ruby-on-rails,ruby,validation,ruby-on-rails-4,associations
An Organization model has a 1:many association with a User model. I have the following validation in my User model file: belongs_to :organization validates_presence_of :organization_id, :unless => 'usertype==1' If usertype is 1, it means the user will have no organization associated to it. For a different usertype the presence of...

## Loop until i get correct user

ruby,redis
I have users stored in Redis and want to be able to call only certain subsets from a set, if i don't get the correct user back i want to put it back in the set and then try again until i get one of the desired users @redis =...

## RSpec test for rake task

I have created a custom rake task that deletes all items that are >= 7 days old. I am trying to write a RSpec test for this new task but it seems like my task isn't really running in the test. I have tested the task manually and it works...

## How to get return value from a forked / spawned process in Ruby?

ruby,process,output,fork,spawn
My simple test program: pid = Process.spawn("sleep 10;date") How can I place the output (eg stdout) of the "date" command in a variable when it is available? I don't want to use a file for the data exchange....

## Same enum values for multiple columns

ruby-on-rails,ruby,enums
I need to do something like this: class PlanetEdge < ActiveRecord::Base enum :first_planet [ :earth, :mars, :jupiter] enum :second_planet [ :earth, :mars, :jupiter] end Where my table is a table of edges but each vertex is an integer. However, it seems the abvove is not possible in rails. What might...

## Ruby access words in string

ruby
I don't understand the best method to access a certain word by it's number in a string. I tried using [] to access a word but instead it returns letter. puts s # => I went for a walk puts s[3] # => w ...

## How to flatten a structure of embedded Set and Hash

ruby,recursion
I would like to convert an embedding structure into a flat one. An embedding structure is a set of 0 or more objects, such as: a string or a hash having some string as key and some other embedding structure as value. A flat structure is a set of arrays...

## In Ruby how to put multiple lines in one guard clause?

ruby-on-rails,ruby
I have the following line of code : if params[:"available_#{district.id}"] == 'true' @deliverycharge = @product.deliverycharges.create!(districtrate_id: district.id) delivery_custom_price(district) end Rubocop highlight it and asks me to use a guard clause for it. How can I do it? EDIT : Rubocop highlighted the first line and gave this message Use a guard...

## Dividing by half in ruby to create an effective calculator

ruby,calculator
For the past while I've been working on a calculator, but have run into problems when needing to divide by a half. I'll add the offending bit of code along with a loop to keep it open below. on = true while on == true do half = 1.0 /...

## Using Ruby Pathname to access relative directory

ruby,path,pathname
Given I have a relative path pointing to a directory how can I use it with Ruby's Pathname or File library to get the directory itself? p = Pathname.new('dir/') p.dirname => . p.directory? => false I have tried './dir/', 'dir/', 'dir'. What I want is p.dirname to return 'dir'. I...

## Stack level too deep because recursion

I have a model named Tweet. The columns of the Tweet model are: -id -content -user_id -picture -group -original_tweet_id Every tweet can have one or multiple retweets. The relation happens with the help of original_tweet_id. All the tweets have original_tweet_id nil , whilst the retweets contain the id of the...

ruby-on-rails,ruby,rest,activerecord,one-to-many
I'm creating a rails application that is a backend for a mobile application. The backend is implemented with a RESTful web API. Currently I am trying to add gamification to the platform through the use of badges that can be earned by the user. Right now the badges are tied...

## Ruby boolean logic: some amount of variables are true

ruby
Let say I have 3 variables: a, b, c. How can I check that just zero or one of them is true?...

## Split an array into slices, with groupings

arrays,ruby,enumerable
I've got some Ruby code here, that works, but I'm certain I'm not doing it as efficiently as I can. I have an Array of Objects, along this line: [ { name: "foo1", location: "new york" }, { name: "foo2", location: "new york" }, { name: "foo3", location: "new york"...

## Map with accumulator on an array

ruby,inject
I'm looking to create a method for Enumerable that does map and inject at the same time. For example, calling it map_with_accumulator, [1,2,3,4].map_with_accumulator(:+) # => [1, 3, 6, 10] or for strings ['a','b','c','d'].map_with_accumulator {|acc,el| acc + '_' + el} # => ['a','a_b','a_b_c','a_b_c_d'] I fail to get a solution working. I...

## Saying there are 0 arguments when I have 2? Trying to open a CSV file to write into

ruby,file,csv,dir
I'm trying to read from a CSV file and codify people into groups using an equation. I append the name of their group they fall into to the end of the array that their row creates. Then I write it to a new file so I don't overwrite the original...

## String#scan not capturing all occurences

ruby,regex
I'm facing a very strange behaviour with ruby String#scan method return. I have this code below and I can't find out why "scan" doesn't return 2 elements. str = "10011011001" regexp = "0110" p str.scan(/(#{regexp})/) ==> [["0110"]] String "str" clearly contains 2 occurences of pattern "0110". I want to fetch...