Enum.cons/3

258 views
Skip to first unread message

TR NS

unread,
Aug 5, 2013, 9:38:29 AM8/5/13
to elixir-l...@googlegroups.com
I have a program that takes pairs of letters and does an ergonomic analysis of there location on a keyboard layout. I do this by iterating over the letters of the top 1000 words in the english language. To do that I need each pair of letters of a word where the last letter of the previous pair becomes the first letter of the current pair. I will give an example in Ruby which has Enumerable#each_cons:

    word = "word".each_char.to_a
    word.each_cons(2).to_a  => [["w", "o"], ["o", "r"], ["r", "d"]]

More examples to clarify:

    word.each_cons(3).to_a    => [["w", "o", "r"], ["o", "r", "d"]]
    word.each_cons(1).to_a    => [["w"], ["o"], ["r"], ["d"]]
    word.each_cons(4).to_a    => [["w", "o", "r", "d"]]
    word.each_cons(5).to_a    => []

To this end it would be helpful to me if Elixir had Enum.cons/3.

    Enum.cons(word, 2, fn(l1, l2) -> ... end)

I'm kind of stuck on my program right now (my first Elixir program) b/c I am not even sure how to implement something equivalent to cons in my code.

Dave Thomas

unread,
Aug 6, 2013, 12:12:32 AM8/6/13
to elixir-l...@googlegroups.com

Here's one way to do it:

defmodule Cons do

  def each_cons(list, n // 2), do: _each_cons(list, n, [])

  defp _each_cons(list,  n, result) when length(list) < n do
    Enum.reverse result
  end

  defp _each_cons(list = [_ | tail], n, result) do
    _each_cons(tail, n, [Enum.take(list, n)|result])
  end
end

IO.inspect Cons.each_cons('words')     # → ['wo', 'or', 'rd', 'ds']
IO.inspect Cons.each_cons('words', 3)  # → ['wor', 'ord', 'rds']
IO.inspect Cons.each_cons('words', 4)  # → ['word', 'ords']

Dave





--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

TR NS

unread,
Aug 6, 2013, 3:40:16 PM8/6/13
to elixir-l...@googlegroups.com, da...@pragprog.com


On Tuesday, August 6, 2013 12:12:32 AM UTC-4, Dave Thomas wrote:

Here's one way to do it:

defmodule Cons do

  def each_cons(list, n // 2), do: _each_cons(list, n, [])

  defp _each_cons(list,  n, result) when length(list) < n do
    Enum.reverse result
  end

  defp _each_cons(list = [_ | tail], n, result) do
    _each_cons(tail, n, [Enum.take(list, n)|result])
  end
end

IO.inspect Cons.each_cons('words')     # → ['wo', 'or', 'rd', 'ds']
IO.inspect Cons.each_cons('words', 3)  # → ['wor', 'ord', 'rds']
IO.inspect Cons.each_cons('words', 4)  # → ['word', 'ords']
That allowed me to get 'er done. Thanks Dave.
 

Doug Ramsay

unread,
Sep 11, 2015, 9:09:35 PM9/11/15
to elixir-lang-core, da...@pragprog.com
Hi,

I'm still very much an Elixir noob, but was trying to figure out a solution for the longest repeating substring within a string, and thought an each_cons implementation would work well. I came across this via Google, but the code as is doesn't seem to compile.

I took a stab at my own solution, but it seems inefficient. I would love any feedback or tips:

defmodule Cons do
  def each_cons([], _), do: []

  def each_cons(list, num) when length(list) < num, do: []

  def each_cons(list, num) do
    [ _ | tail ] = list
    cons = Enum.take(list, num)
    [ cons | each_cons(tail, num) ]
  end  
end

Greg Vaughn

unread,
Sep 11, 2015, 10:24:22 PM9/11/15
to elixir-l...@googlegroups.com
Hi Doug! Nice to see you in the neighborhood.

I used Dave's each_cons implementation in a kata I did for a Project Euler problem of scoring poker hands. Now that I look at it, it's a bit outdated too (old // syntax to specify default values instead of \\) but it is very much similar to yours: https://github.com/gvaughn/elixir_kata/blob/master/poker/lib/poker/hand.ex#L79 except that the "result" accumulator is passed along.

Do you have a link to what Google found for you and any compilation errors?

I also suggest caution about your intuition for what's efficient or not in Elixir.

-Greg
> To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/ba5a0946-b593-47ec-819f-f52d92e58f51%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

eksperimental

unread,
Sep 11, 2015, 10:42:02 PM9/11/15
to elixir-l...@googlegroups.com
Hi Doug,
Could you please give a few examples of what input and output you
expect. actually if they can be in the for a _test.exs or a doctest,
would be great!
> >> send an email to elixir-lang-co...@googlegroups.com <javascript:>.

eksperimental

unread,
Sep 11, 2015, 10:44:08 PM9/11/15
to elixir-l...@googlegroups.com
Sorry Doug, but you should send these kind of emails to
elixir-l...@googlegroups.com
as these list is exclusively reserved for things related to the
development of the Elixir language itself.


On Fri, 11 Sep 2015 18:09:35 -0700 (PDT)
Doug Ramsay <dougr...@gmail.com> wrote:

> >> send an email to elixir-lang-co...@googlegroups.com <javascript:>.

Doug Ramsay

unread,
Sep 13, 2015, 8:11:13 PM9/13/15
to elixir-lang-core, eksper...@autistici.org
Will do eksperimental - thanks for the tip!

Greg - good to see you as well! Posted a couple gists - we can move the conversation there:

Tallak Tveide

unread,
Sep 15, 2015, 1:23:45 AM9/15/15
to elixir-lang-core
`Enum.chunk` is probably what you are looking for. It covers Ruby's `each_cons` and `each_slice` roughly
Reply all
Reply to author
Forward
0 new messages