# Iterating or Pattern Matching on a certain conditions

I have a pretty straight-forward problem, but struggle to make it clear and concise (is that possible at all!?).

So having two lists:

``````list_1 = ["\$100", "\$200", "\$300"]
list_2 = ["bob", "\$200", "sam"]
``````

success output should be:

``````"bob: \$100, sam: \$300"
``````

fail output:

``````list_1 = ["\$100", "\$200", "\$300"]
list_2 = ["bob", "bob", "sam"]
false
``````

Obviously, `list_2` (or our pattern) might be different, but if prices are matching we should return a success output similar to above.

I approached it right away by:

``````iex(2)> Enum.zip(["bob", "\$200", "sam"], ["\$100", "\$200", "\$300"])
[{"bob", "\$100"}, {"\$200", "\$200"}, {"sam", "\$300"}]
``````

and then with a lot of conditional logic and accumulators in Enum.reduce solved the problem, but itâ€™s super uglyâ€¦ When my Elixir code is ugly - Iâ€™m always questioning myself, since there is always another and cleaner way.

How would you approach this? Is there a way?

Thank you all in advance!

Based solely on what youâ€™ve posted (I donâ€™t really understand why `list_2` has a mix of names and amounts):

``````list_1 = ["\$100", "\$200", "\$300"]
list_2 = ["bob", "\$200", "sam"]

pairs = Enum.zip(list_1, list_2)

unmatched_pairs = Enum.reject(pairs, fn {l1, l2} -> l1 == l2 end)

if length(unmatched_pairs) == length(list_1) do
false
else
unmatched_pairs
|> Enum.map(fn {l1, l2} -> "#{l1}: #{l2}" end)
|> Enum.join(", ")
end
``````

(Edited to fix a bug - was looking at `length(pairs)` without filtering first)

1 Like

@al2o3cr
Matt, thank you so much! Always always appreciate your wisdom and willingness to help the community!

Iâ€™m sorry if my explanation wasnâ€™t very clear (I know you a huge proponent of clear statements to make it easier for people to help efficiently).

``````I donâ€™t really understand why list_2 has a mix of names and amounts
``````

Well, thatâ€™s the thing - itâ€™s a filter pattern (if I can call it this way). Let me give a couple of more real examples to explain it better:

``````1.
list_1 = ["\$100", "\$200", "\$300"]
list_2 = ["bob",  "\$200", "sam"]

is a success case, since second elements in both lists are identical
(and we don't need to expose it in our output).

And output will be:
"bob: \$100, sam: \$300"
(
- "bob" is a first element in the list_2 and
- corresponding first element in the list_2 is "\$100" and etc
)
``````
``````2.
list_1 = ["\$100", "\$200", "\$300"]
list_2 = ["\$100",  "tom", "sam"]

is a success case for the same reasons in the ex 1.

And output will be:
"tom: \$200, sam: \$300"
(
- "tom" is a second element in the list_2 and
- corresponding second element in the list_2 is "\$200" and etc
)
``````
``````3.
list_1 = ["\$100", "\$200", "\$300"]
list_2 = ["bob",  "tom", "sam"]

is a fail case .

We don't have any corresponding matches on price (there are only names in the list_2)
``````

I run your example, but not sure why we need `if` statement to check if `pairs` size equal to `list_1`?!
It will always be the same, no? Am I missing something here?

Again, really appreciate all your possible help here!

Nope, youâ€™re not missing anything - that was a bug!

The intent is to check the length of the zipped pairs after filtering out ones like `{"\$200", "\$200"}` - if none of the pairs got filtered out, we need to return `false` (a â€śfail caseâ€ť).

1 Like

i too dont think i understand the 2 lists, but here is what i have for your 3 tests/examples:

``````iex(5)> test1 = {["\$100", "\$200", "\$300"], ["bob",  "\$200", "sam"]}
{["\$100", "\$200", "\$300"], ["bob", "\$200", "sam"]}
iex(6)> test2 = {["\$100", "\$200", "\$300"], ["\$100",  "tom", "sam"]}
{["\$100", "\$200", "\$300"], ["\$100", "tom", "sam"]}
iex(7)> test3 = {["\$100", "\$200", "\$300"],["bob",  "tom", "sam"]}
{["\$100", "\$200", "\$300"], ["bob", "tom", "sam"]}
iex(8)> [test1, test2, test3] |>
...(8)> Enum.map(fn {list1, list2} ->
...(8)>   Enum.zip(list1, list2) |>
...(8)>   Enum.reduce({false, []}, fn
...(8)>     {l1,l1}, {_, pairs} -> {true, pairs}
...(8)>     l1l2, {result, pairs} -> {result, [l1l2|pairs]}
...(8)>   end)
...(8)> end)
[
true: [{"\$300", "sam"}, {"\$100", "bob"}],
true: [{"\$300", "sam"}, {"\$200", "tom"}],
false: [{"\$300", "sam"}, {"\$200", "tom"}, {"\$100", "bob"}]
]
``````

result/accumulator of the `reduce` is a tuple: `{PASS-FAIL, PAIRS}`

1 Like

Format more nicely in production code, but hereâ€™s a quick iex solution

``````iex(91)> list_1 = ["\$100", "\$200", "\$300"]
["\$100", "\$200", "\$300"]
iex(92)> list_2 = ["\$100",  "tom", "sam"]
["\$100", "tom", "sam"]
iex(93)> pairs = Enum.zip(list_1, list_2)
[{"\$100", "\$100"}, {"\$200", "tom"}, {"\$300", "sam"}]
iex(94)> if Enum.any?(pairs, &match?({a, a}, &1)), do: Enum.join((for {a, b} <- pairs, a != b, do: "#{b}: #{a}"), ", "), else: false
"tom: \$200, sam: \$300"
``````
2 Likes

@czrpb and @gregvaughn
Thank you so much for your input and sorry about my delay here! That pandemic definitely is not over, got sick finally

Again, really appreciate it!

1 Like