mackeyja92

mackeyja92

`Enum.map_every/3` but with start offset

There is sometimes cases where you want to map every nth item starting on the nth item. Eg map every 2nd item starting on the 2nd one. Currently the map_every/3 always gives back the first item in the enumerable and then every nth item. I propose to add an optional parameter to the function for the offset for the first item. Another option would be to add a parameter to start on the nth item instead but that’s probably less flexible than the offset. What’s your thoughts? Is there another way to do this with the existing APIs?

Most Liked

tomekowal

tomekowal

I believe that is a perfectly fine solution. If you need to perform different operations on even and odd elements you could also try chunking the list.

E.g.

[1,2,3,4,5,6]
|> Enum.chunk_every(2)
# [[1,2], [3,4], [5,6]]
|> Enum.map(fn [first, second] -> [first*2, second*3] end)
|> List.flatten
# [2, 6, 6, 12, 10, 18]

That doubles every odd element and triples every even one.

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

@mackeyja92 I’d probably use Enum.drop.
eg: “Map every 4th thing starting on the 2nd thing”

list |> Enum.drop(2) |> Enum.map_every(4, fun)
mackeyja92

mackeyja92

The problem with drop is it removes the items from the list. If you only need to do a certain operation on nth items but need to do another operation on the whole list after you’re stuck with removing items and storing in a temporary list and then pushing them back on the front after the map_every.

A real world example is the Luhn checksum.

# Reverse them first                                                                                                                                                                                                                                                                        
numbers = Enum.reverse(numbers)                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                                            
# Pop the first one off because elixir always does the first one when using map_every                                                                                                                                                                                                       
{first, numbers} = List.pop_at(numbers, 0)                                                                                                                                                                                                                                                  
                                                                                                                                                                                                                                                                                            
numbers                                                                                                                                                                                                                                                                                     
|> Enum.map_every(2, fn num ->                                                                                                                                                                                                                                                              
  num = num * 2                                                                                                                                                                                                                                                                             
  # If the number after doubling is greater than 9 then subtract 9                                                                                                                                                                                                                          
  if num > 9 do                                                                                                                                                                                                                                                                             
    num - 9                                                                                                                                                                                                                                                                                 
  else                                                                                                                                                                                                                                                                                      
    num                                                                                                                                                                                                                                                                                     
  end                                                                                                                                                                                                                                                                                       
end)                                                                                                                                                                                                                                                                                        
# Put the first one back                                                                                                                                                                                                                                                                    
|> List.insert_at(0, first)                                                                                                                                                                                                                                                                 
# Sum them all                                                                                                                                                                                                                                                                              
|> Enum.sum()                                                                                                                                                                                                                                                                               
# If the modulo of 10 is 0 then it is a valid checksum                                                                                                                                                                                                                                      
|> Kernel.rem(10)                                                                                                                                                                                                                                                                           
|> Kernel.==(0)   

Last Post!

shjeon0730

shjeon0730

found a simple solution:
basic concept is, adding a dummy value at the beginning, and choose tail later.

list=[1,2,3,4,5]
Enum.map_every(list, 2, & &1+10)
[11, 2, 13, 4, 15]
[99 | list] |> Enum.map_every(2, & &1+10) |> tl
[1, 12, 3, 14, 5]

for more offset, comprehension would work.

for i <- 1..5 do i end ++ list |> Enum.map_every(7, & &1+10) |> Enum.drop(5)
[1, 2, 13, 4, 5]

if it is just alternate pattern and need to choose offset 0 or 1, it might be useful

Where Next?

Popular in Discussions Top

und0ck3d
Hello everyone! A few days ago I’ve created a topic here about how people were creating CMSs with Elixir and Phoenix. I’ve been studying...
New
jer
I’ve been using umbrellas for a while, and generally started off (on greenfield projects at least) by isolating subapps based on clearly ...
New
Nvim
Anybody knows a comprehensive comparison of Django and Phoenix, thanks for the help. Where are they similar? Where do they differ the m...
New
Nvim
Elixir appears to be a superior language to Python. I don’t see any advantage of Python over Elixir. Are there any?
New
opsb
We’re considering our architecture from a viewpoint of scaling our traffic heavily over the next 6 months. Our current deployment is runn...
New
pillaiindu
I want to convert a Phoenix LiveView CRUD website to a CRUD mobile app. What do you think is the easiest way to do so?
New
matthias_toepp
I’d love to hear what people think about Wisp, the new Gleam web framework started by Gleam’s primary creator Louis Pilfold. Gleam, alon...
New

Other popular topics Top

minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 40165 209
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 44265 214
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New

We're in Beta

About us Mission Statement