Function to return the second letter of each word in Elixir

I need a function that accepts a string as a paramater and the function should return the second letter of each word.

Example Module.function(“There are many books”)
#result → hrao

CODE

defmodule Main do

  def names(phrase) do 
    var = String.split(phrase)
  end

  def loop(var) do
    Enum.map(var, fn x ->
      String.at(x, 2)
    end)
  end
end

What if a word less than 2 letters? such as “This is a cat”

Assuming all words have more than 2 letters

What have you tried? You’re asking community members to do work for you and this community is incredibly helpful. But in return, it is appropriate to at least show what you’ve tried already.

5 Likes

What you need is very easily achievable with the functions in the String and Enum module. Give it a try and post again if you succeed partially but can’t quite get there.

1 Like
defmodule Main do

  def names(phrase) do 
    var = String.split(phrase)
  end

  def loop(var) do
    Enum.map(var, fn x ->
      String.at(x, 2)
    end)
  end
end

Main.names("there is good a good pizza parlor")
|> IO.inspect()

I want to do,

  1. Split the string into elements
  2. Iterate through all elements
  3. Extract each of their 2nd letters
  4. Return string containing all the 2nd letters
  1. Split the string into elements

String.graphemes

  1. Iterate through all elements

Enum.map

  1. Extract each of their 2nd letters

Enum.at

  1. Return string containing all the 2nd letters

Enum.join

1 Like

Tried but i think there is a problem with the syntax

OK, you should fix it. Hard to help without seeing sth, even if I myself think have already produced all Elxir syntax errors possible.

defmodule Main do

  def names(phrase) do 
    var = String.split(phrase)
  end

  def loop(var) do
    Enum.map(var, fn x ->
      String.at(x, 2)
    end)
  end
end

Main.names("there is good a good pizza parlor")
|> IO.inspect()

loop is never called (and its not a loop, you should spend some time to grasp the basics of functional languages, highly recommended: https://exercism.org - Elixir track).

You are nearly there.

iex(6)> phrase = "There are many books"
"There are many books"
iex(8)> var = String.split(phrase)
["There", "are", "many", "books"]
iex(9)> Enum.map(var, fn x ->
...(9)>       String.at(x, 2)
...(9)>     end)
["e", "e", "n", "o"]

Thanks for showing your work. You’ve made a good start. A few things to help get you a bit closer:

  1. String.split/1 will split on Unicode whitespace. That’s a reasonable default for Latin text. If you are working with difference languages it won’t be the correct approach. If you need a more complete “split at words” implementation you can look this library.

  2. Binary pattern matching is very good in elixir and matches can be put into function heads. Binary pattern matching is the fastest way to extract known parts of a string. For example:

iex> <<first::utf8, second::utf8, _rest::binary>> = "there"
"there"
iex> second
104
  1. You’ll notice that second is 104 which is the code point of “h”. You can convert that back to a string if you need with List.to_string([second]) but in many cases you don’t need to do that. It depends.
iex> List.to_string([second])
"h"
  1. Putting it together and returning the first letter if the word is one char long:
defmodule Names do
  def names(names) do
    names
    |> String.split()
    |> Enum.map(&extract_second/1)
    |> List.to_string()
  end
  
  def extract_second(<<_first::utf8, second::utf8, _rest::binary>>), do: second
  def extract_second(<<first::utf8>>), do: first
end
  1. Example:
iex> Names.names "there is good a good pizza parlor"                                
"hsoaoia"
2 Likes

I can hear a brain exploding in the distance. :grimacing:
Great solution, but maybe a little advanced for now?

2 Likes

Yes thats true

Thanks for that, I really appreciate it. But do you have a much simpler approach

@Sebb’s answer will work perfectly well. My answer isn’t really all that much different - but the difference is a very valuable piece of Erlang/Elixir which is binary pattern matching.

Its a good thing to get familiar with as you get more comfortable with Elixir. And I am more than happy (as I’m sure others are) to explain any “head explosion” parts :slight_smile:

1 Like

its actually his(?) own solution.

1 Like

Look at my post, I just reordered your code. And it works. You just have to join it (Enum.join).

apropos exploding brains:

iex(10)> for <<_::utf8, g::utf8, _::binary>> <- ~w(There are many books), do: g
'hrao'

works with @Ljzn example also:

iex(11)> for <<_::utf8, g::utf8, _::binary>> <- ~w(This is a cat), do: g        
'hsa'

string result:

iex(13)> for <<_::utf8, g::utf8, _::binary>> <- ~w(This is a cat), into: <<>>, do: <<g>>
"hsa"

Just to show where the voyage into Elixir can lead you to. Secret fact: its the best language.

3 Likes

Nice, thanks for that, I was just there :grinning: :grinning: