How to map/collect with index in Ruby?
If you're using ruby 1.8.7 or 1.9, you can use the fact that iterator methods like each_with_index
, when called without a block, return an Enumerator
object, which you can call Enumerable
methods like map
on. So you can do:
arr.each_with_index.map { |x,i| [x, i+2] }
In 1.8.6 you can do:
require 'enumerator'
arr.enum_for(:each_with_index).map { |x,i| [x, i+2] }
Using each_with_index with map
a.to_enum.with_index(1).map { |element, index| "#{index}. #{element}" }
or
a.map.with_index(1) { |element, index| "#{index}. #{element}" }
with_index(1)
makes the index of the first element 1
.
In the first solution the array is converted to an enum, and in the second solution the array is directly mapped.
Enumerate or map through a list with index and value in Dart
There is a asMap
method which converts the list to a map where the keys are the index and values are the element at index. Please take a look at the docs here.
Example:
List _sample = ['a','b','c'];
_sample.asMap().forEach((index, value) => f);
eachWithIndex loop is unstable
result?.data is instance of list (look at the data class after "as Map" operation it becomes ArrayList1_groovyProxy...)
You can iterate through list(and build the map if you need):
Map data = [:]
result?.data?.eachWithIndex { dataItem, idx ->
if (dataItem) {
log.info dataItem
data[idx] = dataItem
}
}
If this happends time to time - probably your result?.data already comes sometimes as List and sometimes as Map
Groovy: Different behaviour observed using the eachWithIndex method
When you use the no-arg version of eachWithIndex
, it
is the current entry in the Map. That means that it.key
and it.value
return what you expect.
When you use the two-arg version of eachWithIndex
, again, it
is the current entry in the Map and i
is the current index. You're printing i
, the index, and then since you are only printing it
, you are getting the result of it.toString()
, which formats the map entry as "${it.key}=${it.value}"
Loop through Map in Groovy?
Quite simple with a closure:
def map = [
'iPhone':'iWebOS',
'Android':'2.3.3',
'Nokia':'Symbian',
'Windows':'WM8'
]
map.each{ k, v -> println "${k}:${v}" }
Ruby : Choosing between each, map, inject, each_with_index and each_with_object
A more tl;dr answer:
How to choose between each, map, inject, each_with_index and each_with_object?
Use
#each
when you want "generic" iteration and don't care about the result. Example - you have numbers, you want to print the absolute value of each individual number:numbers.each { |number| puts number.abs }
Use
#map
when you want a new list, where each element is somehow formed by transforming the original elements. Example - you have numbers, you want to get their squares:numbers.map { |number| number ** 2 }
Use
#inject
when you want to somehow reduce the entire list to one single value. Example - you have numbers, you want to get their sum:numbers.inject(&:+)
Use
#each_with_index
in the same situation as#each
, except you also want the index with each element:numbers.each_with_index { |number, index| puts "Number #{number} is on #{index} position" }
Uses for
#each_with_object
are more limited. The most common case is if you need something similar to#inject
, but want a new collection (as opposed to singular value), which is not a direct mapping of the original. Example - number histogram (frequencies):numbers.each_with_object({}) { |number, histogram| histogram[number] = histogram[number].to_i.next }
EachWithIndex groovy statement
These are plain methods but they follow quite a specific pattern - they take a Closure
as their last argument. A Closure is a piece of functionality that you can pass around and call when applicable.
For example, method eachWithIndex might look like this (roughly):
void eachWithIndex(Closure operation) {
for (int i = 0; this.hasNext(); i++) {
operation(this.next(), i); // Here closure passed as parameter is being called
}
}
This approach allows one to build generic algorithms (like iteration over items) and change the concrete processing logic at runtime by passing different closures.
Regarding the parameters part, as you see in the example above we call the closure (operation
) with two parameters - the current element and current index. This means that the eachWithIndex method expects to receive not just any closure but one which would accept these two parameters. From a syntax prospective one defines the parameters during closure definition like this:
{ elem, index ->
// logic
}
So ->
is used to separate arguments part of closure definition from its logic. When a closure takes only one argument, its parameter definition can be omitted and then the parameter will be accessible within the closure's scope with the name it
(implicit name for the first argument). For example:
[1,2,3].each {
println it
}
It could be rewritten like this:
[1,2,3].each({ elem ->
println elem
})
As you see the Groovy language adds some syntax sugar to make such constructions look prettier.
Groovy eachWithIndex multiple statements
The following code:
[1,2,3,4,5,6,7].eachWithIndex { num, idx ->
int a = 2
int b = 3
println "${a + b} ${idx}: ${num}"
}
emulates your example, works, and produces the following output:
~> groovy solution.groovy
5 0: 1
5 1: 2
5 2: 3
5 3: 4
5 4: 5
5 5: 6
5 6: 7
~>
You don't need the second level of curly braces. Also in your code you have misspelled int
as nt
, you don't need the semicolons at the line endings, and in general groovy string interpolation is more readable than appending to the string using +
.
To generate a list for each map key as iterating through list?
You can create a map using [ key: value]
notation. Since your value is an array of two elements you can simply create it using [element1,element2]
notation, and then you can add the object to the map using <<
operator.
So this myMap << [ (object) : [element1,element2]]
can do the job.
In your code:
def myMap = [:]
anotherList.each{
object -> //here i do some work to get two elements
def element1 = ..
def element2 = ..
// so here i need to generate a list for the two elements with index 0 and 1
myMap << [ (object) : [element1,element2]]
}
return myMap
Note that I use (object)
to evaluate the key, because if I use directly object
the literal is used as key in the map instead of the value.
Hope this helps,
UPDATED BASED ON OP COMMENT:
If I understand well your requirements you want that map keys are the index instead of the value isn't it? To do so you can use eachWithIndex
instead of each
for example:
def myMap = [:]
def anotherList = ['a','b','c','d']
anotherList.eachWithIndex{ object,index -> //here i do some work to get two elements
def element1 = object + 'z'
def element2 = object + 'x'
// so here i need to generate a list for the two elements with index 0 and 1
myMap << [ (index) : [element1,element2]]
}
return myMap //Result: [0:[az, ax], 1:[bz, bx], 2:[cz, cx], 3:[dz, dx]]
Related Topics
How to Replace an Array's Element
Can't Install Rmagick and Imagemagick on Windows 7
How to Scroll a Web Page Using Watir
How Do Get a Random Datetime Rounded to Beginning of Hour in Rails
How to Join a Table and Count Records in Rails 3
How to Extend a Class from an Initializer and Have It Reload in Development Environment
Unwanted Form Parameters Being Appended to Pagination Links
Why Do I Need Asterisk Before an Array
What Do I Need to Do to Get Hash.From_Xml() to Work
Using Ruby 2.0 on Amazon Opsworks
Error Connecting to Redis on 127.0.0.1:6379 (Errno::Econnrefused) - Wercker
When Trying to Generate a Model with Rails and Postgresql, the Command Hangs Without Error
Sinatra - How to Get the Server's Domain Name
Git Post-Receive Hook Not Running Bundle Install
Celluloid Async Inside Ruby Blocks Does Not Work