Working in elixir and I have a list I'd like to reduce to only unique keys, merging the list elements together:
[{"abc", [%{a: "a"}]},{"bcd", [%{a: "a"}]},{"bcd", [%{a: "b"}]}]
can anyone think of a succinct way to combine elements to arrive at
[{"abc", [%{a: "a"}]}, {"bcd", [%{a: "a"}, %{a: "b"}]}]
Enum.group_by/3 comes to the rescue:
▶ list = [{"abc", [%{a: "a"}]},{"bcd", [%{a: "a"}]},{"bcd", [%{a: "b"}]}]
▶ list |> Enum.group_by(fn {k, _} -> k end, fn {_, [v]} -> v end)
#⇒ %{"abc" => [%{a: "a"}], "bcd" => [%{a: "a"}, %{a: "b"}]}
If you insist on having a list of tuples in the end, just append Enum.into/2 to the chain:
|> Enum.into([])
#⇒ [{"abc", [%{a: "a"}]}, {"bcd", [%{a: "a"}, %{a: "b"}]}]
Generic solution that works for values lists of any size:
▶ list
▷ |> Enum.group_by(fn {k, _} -> k end, fn {_, v} -> v end)
▷ |> Enum.map(fn {k, v} -> {k, List.flatten(v)} end)
#⇒ [{"abc", [%{a: "a"}]}, {"bcd", [%{a: "a"}, %{a: "b"}]}]
Related
I have a list of lists
>> list = [[1,""],[2,"b"],[3,""],[4,"c"]]
I want to delete the lists that contains "" element
>>list = [[2,"b"],[4,"c"]]
I'm trying to find something like
list = List.delete(list,[any,""])
You could combine Enum.reject/2 with Enum.member?/2 and reject any list that contains empty string
iex> Enum.reject([[1,""],[2,"b"],[3,""],[4,"c"]], &Enum.member?(&1, ""))
[[2, "b"], [4, "c"]]
If your inner lists are always the same two-item style and you're only wanting to check the second item, you could also use an anonymous function
iex> Enum.reject([[1,""],[2,"b"],[3,""],[4,"c"]], fn [_, b] -> b == "" end)
[[2, "b"], [4, "c"]]
or a comprehension that does pretty much the same thing
iex> for [a, b] when b != "" <- [[1,""],[2,"b"],[3,""],[4,"c"]], do: [a, b]
[[2, "b"], [4, "c"]]
I am trying to use recursion and higher-order functions to do something to the first element of a list and then to every other element in the list, so for example add 3 to the 1st, 3rd, 5th.. etc.
The problem I am having is that it gives me the non-exhaustive pattern error. Any help would be appreciated. Here is what I have so far:
applyToEveryOther :: (a -> b) -> [a] -> [b]
applyToEveryOther _ [] = []
applyToEveryOther f (x:y:xs) = f x : applyToEveryOther f xs
and these are some additional lines that I have tried but don't help:
applyToEveryOther _ [x] = f x
applyToEveryOther f [x] = f x
The single element case should also return a List (of type [b]):
applyToEveryOther f [x] = [f x]
Another solution that doesn't use explicit recursion, but just higher-order functions:
import Data.List (cycle)
applyToEveryOther f = zipWith ($) (cycle [f, id])
cycle creates an infinite list of alternating functions f, id, f, id, etc.
zipWith ($) applies the functions in the list to the corresponding elements of your input list.
[(+1), id, (+1), id, (+1), id, (+1), id, ...]
[ 1, 2, 3, 4, 5, 6, 7, 8 ]
=============================================
[ 2, 2, 4, 4, 6, 6, 8, 8 ]
(Hat tip: the problem of applying a list of functions piecewise to a list of arguments, along with a solution using zipWith ($), appeared recently on the 1HaskellADay twitter feed.)
(My own inferior solution was to use the ZipList type constructor found in Control.Applicative; applied here, it would look something like
import Control.Applicative
applyToEveryOther f xs = let fs = cycle [f,id]
in getZipList (ZipList fs <*> ZipList xs)
)
For example, if i have a function argument of findProduct([[1,2,3],[1,5,6]]) how can i figure out the product of the 2 sublists and then add them into a new list with result [6,30]?
productFn = fn(list) -> Enum.reduce(list, &*/2) end
my_list = [[1, 2, 3], [1, 5, 6]]
Enum.map(my_list, productFn) # => [6, 30]
If you are not familiar with the & operator (more info here):
productFn = fn(list) -> Enum.reduce(list, &*/2) end
#is equivalent to:
productFn = fn(list) -> Enum.reduce(list, fn(item, acc) -> item * acc end) end
And,
Enum.map(list, productFn)
is equivalent to:
Enum.map(list, fn(item) -> productFn.(item) end)
You can use Enum.reduce/2 to reduce each list with an accumulator, and then return the new list with those two elements:
defmodule MyProduct do
def findProduct(list_of_lists) do
Enum.map(list_of_lists, fn(list) -> Enum.reduce(list, fn(x, acc) -> x * acc end) end)
end
end
Given a list of items, how may we filter for a specific struct?
Example:
We need only %TL.DocumentAttributeFilename{} from the items in the list
lst1 = [%TL.DocumentAttributeImageSize{h: 1280, w: 960}, %TL.DocumentAttributeFilename{file_name: "422305695_81769.jpg"}]
lst2 = [%TL.DocumentAttributeVideo{duration: 7, h: 224, w: 264}, %TL.DocumentAttributeFilename{file_name: "animation.gif.mp4"}, %TL.DocumentAttributeAnimated{}]
You can use for for this:
Given:
defmodule A do
defstruct [letter: :a]
end
defmodule B do
defstruct [letter: :b]
end
You can do:
iex(1)> list = [%A{}, %B{}, %A{}, %A{}, %B{}]
[%A{letter: :a}, %B{letter: :b}, %A{letter: :a}, %A{letter: :a}, %B{letter: :b}]
iex(2)> for %A{} = a <- list, do: a
[%A{letter: :a}, %A{letter: :a}, %A{letter: :a}]
This works because for ignores all items that don't match the given pattern.
You can also use Enum.filter and pattern match using function with multiple bodies:
list = [%A{number: 1}, %B{number: 2}, %A{number: 3}, %A{number: 4}, %B{number: 5}, %A{number: 6}]
Enum.filter(list, fn
%A{} -> true
_ -> false
end)
This is particularly useful because you can further narrow down using item's properties and guards:
Enum.filter(list, fn
%A{number: n} when n > 4 -> rem(n, 3) == 0
%B{number: n} when n < 2 -> true
_ -> false
end)
You can also use Enum.filter to make it clearer what operation takes place:
Enum.filter( lst1, fn( x ) -> %TL.DocumentAttributeFilename{} == x end )
As Dogbert observed the above expression will keep only those elements of lst1 that are TL.DocumentAttributeFilename structs with default field values - not what you asked for.
Here's a version that will keep all TL.DocumentAttributeFilename structs of lst1:
Enum.filter( lst1, fn( x ) -> x.__struct__ == TL.DocumentAttributeFilename end )
This is a question about rearranging parts of nested lists in Mathematica.
I've got a nested List:
DatenList = {{1, {100, 200}}, {2, {101, 201}}, {3, {102, 202}}};
and want to get another list like
{{1,100},{2,101}}
Is there a neater way than
temp = DatenList[[1 ;; 2, 1]];
temp2 = DatenList[[1 ;; 2, 2]][[;; , 1]];
temp = {temp}~Join~{temp2};
finalList = Transpose[temp]
which yields
{{1, 100}, {2, 101}}
temp2 = DatenList[[1 ;; 2, 2]][[;; , 1]]
can be written shorter as
temp2 = DatenList[[1 ;; 2, 2, 1]]
Otherwise, the whole operation can be done several ways :-
finalList = {#1, First[#2]} & ### DatenList[[1 ;; 2]]
finalList = DatenList[[1 ;; 2]] /. {a_Integer, {b_, _}} :> {a, b}
finalList = Replace[DatenList[[1 ;; 2]], {a_, {b_, _}} :> {a, b}, 1]
finalList = MapThread[{#1, First[#2]} &, Transpose[DatenList[[1 ;; 2]]]]