Get value from a list inside a map elixir

I have a struct that looks like this:

defmodule WarGame.Core.Game do


  defstruct user_cards: [],
            croupier_cards: [],
            user_bets: [],
            bets: [:card_odd, :color_player],
            deck: %{},
            used: [],
            title: nil


  def new(fields) do
    struct!(__MODULE__, fields)
  end

end

I would like to create a function that can take a chosen element of a list bets and move it to user_bets. How could I achieve this? There will be only finite (5) elements in this list.

Map.take/2 should do what you need

So you suggest that I change my list to a map and then use Map.take/2?

Sorry I misread the original post.

Maybe I would do something like this. (it is not the prettiest, but it should work)

index = Enum.find_index(user_cards.bets, &(&1 == :some_term))
{user_bet, bets} = List.pop_at(user_cards.bets, index)
user_bets = [user_bet | user_bets]

%UserCards{user_cards | bets: bets, user_bets: user_bets}

I am not sure that I follow.

In my head I would like to create a function that as an argument takes an element from bets, uses it to pick this bets element and inserts it to user_bets.

Something like this:

`def select_bet(bet) do
    finds bet in %WarGame.Core.Game{}.bets
    inserts it to %WarGame.Core.Game{}.user_bets
end`

In this case, (I thought you also wanted to remove it from the bets)

def select_bet(%Game{bets: bets} = game, bet) when bet in bets do
    %{game | user_bets: [bet | game.user_bets]}
end

def select_bet(game, _bet), do: game

Usually you would want to also pass in the game you are working with in the function.
This will return you a new game with the updated user_bets or the game untouched

2 Likes

Thanks for your time and effort!

When I am trying to run this code I get - (ArgumentError) invalid right argument for operator "in", it expects a compile-time proper list or compile-time range on the right side when used in guard expressions, got: bets

Can also do it like this

def select_bet(%Game{bets: bets} = game, bet) do
  if bet in bets do
    %{game | user_bets: [bet | game.user_bets]}
  else
    game
  end
end
3 Likes

Thanks for your help, I really appreciate it!

If it’s not too much to ask I would be very grateful if you could explain a bit what you did, as I am having hard time understanding it :slight_smile:

Sure, so from the top:
Here we pattern match on the bets inside a game, we could also just done game.bets inside the if statement.

def select_bet(%Game{bets: bets} = game, bet) do

Inside the function, we have a simple if condition, If we find the bet item inside the passed in game’s bets list, then we use the shorthand update syntax for a map.

 %{map| key: new_value}

We also prepend the bet to the user_bets using the list shorthand syntax, This will give us a new list with the bet at the beginning of the list. It is more efficient to put a new element at the beginning of a list, rather than append to the end, appending to the end requires you to traverse the whole list.

[bet | game.user_bets]

If the If condition is not true (bet is not found in bets) then we return the game with no modifications

2 Likes

You are the best!
Now I understand what your code meant and will probably be able to do it on my own next time! That’s so helpful!

THANKS!!!

1 Like

Just to add to the answer… bet in bets can be used as a guard clause.

def select_bet(%Game{bets: bets} = game, bet) 
  when bet in bets, do: %{game | user_bets: [bet | game.user_bets]}
def select_bet(game, _bet), do: game
5 Likes