Multiply list elements in Haskell - list

I want a function which takes the product of the inits of a list and duplicates its elements.
For example the list is: [2, 3, 4, 5].
The product of its inits : [1, 2, 6, 24, 120].
At the end the list should look like this: [1, 1, 2, 2, 2, 6, 6, 6, 6, 24, 24, 24, 24, 24].
My problem is that the [1, 2, 6, 24, 120] should not vary, but i can't solve it, I'm pretty new to haskell. You don't need to modify this code, you can make a new one.
makeSystem :: Integral a => [a] -> [a]
makeSystem l= replicate (l !! 0) ((map product(inits l))!!0) ++ asd (tail l) where
inits [] = [[]]
inits (x:xs) = [[]] ++ map (x:) (inits xs)
An other example: makeSystem [5,2,5,2,5,2]
The result: [1, 1, 1, 1, 1, 5, 5, 10, 10, 10, 10, 10, 50, 50, 100, 100, 100, 100, 100, 500, 500]

For the first part, you can use the standard function scanl:
> scanl (*) 1 [2, 3, 4, 5]
[1,2,6,24,120]
For the second part, zipWith with replicate gets us most of the way there:
> zipWith replicate [2, 3, 4, 5] [1, 2, 6, 24, 120]
[[1,1],[2,2,2],[6,6,6,6],[24,24,24,24,24]]
then we just need to concat these lists.
Putting it all together:
> let makeSystem xs = concat $ zipWith replicate xs (scanl (*) 1 xs)
> makeSystem [2, 3, 4, 5]
[1,1,2,2,2,6,6,6,6,24,24,24,24,24]
> makeSystem [5, 2, 5, 2, 5, 2]
[1,1,1,1,1,5,5,10,10,10,10,10,50,50,100,100,100,100,100,500,500]

Related

Nested sum in Erlang

I have a doubt how can I add the numbers of list including the ones that are on a nested list, for example:
test:nestedSum([1, [2, 3], [4, 5, 6], 7]).
⇒ 28
So far I got this:
nestedSum(L) -> nestedSum(L, 0).
nestedSum([H|T], Acc) ->
nestedSum(T, H + Acc);
nestedSum([], Acc) ->
Acc.
which only works:
test:nestedSum([1, 2, 3, 4, 5, 6, 7]).
⇒ 28
but it does not sum the numbers that are in the nested sum, How can I do it?
You just need to add one clause to the nestedSum/2 function for the case when the head of the list is a list:
% Add this before the two existing clauses.
nestedSum([H|T], Acc) when is_list(H) ->
nestedSum(T, nestedSum(H) + Acc);
With this, your function can now handle any nested list:
1> a:nestedSum([1, [2, 3], [4, 5, 6], 7]).
28
2> a:nestedSum([1, [2, 3], [4, 5, 6], 7, [8, [[[9, [[[[[[10]]]]]]]]]]]).
55
You could use lists:flatten:
nestedSum(L) -> nestedSum(lists:flatten(L), 0).
.
.
Reducing a list is often a one-liner:
lists:foldl(fun(X,Sum) -> X + Sum end, 0, lists:flatten([1, [2, 3], [4, 5, 6], 7])).

insert at every nth index of a list

Is there a standard Elixir function that can insert an element at every nth index of a list?
With a function call and return like:
iex> List.insert_at_every([1,2,3,4,5], 2, Enum.random(["apple","banana"]))
[1, 2, "apple", 3, 4, "apple", 5]
NB the solution proposed by #Dogbert is better by all means, I am posting this for the sake of diversity.
To intersperse the list with a constant value, one might use Enum.chunk_every/2 and Enum.intersperse/2:
iex(1)> [1,2,3,4,5]
...(1)> |> Enum.chunk_every(2)
...(1)> |> Enum.intersperse("banana")
...(1)> |> List.flatten
#⇒ [1, 2, "banana", 3, 4, "banana", 5]
This won’t work if you want to use a function to retrieve an element to intersperse on each iteration. In that case you are to implement the interspersion yourself:
iex(2)> [1,2,3,4,5]
...(2)> |> Enum.chunk_every(2)
...(2)> |> Enum.map(& &1 ++ [Enum.random(~w|banana apple|)])
...(2)> |> List.flatten
#⇒ [1, 2, "banana", 3, 4, "apple", 5, "apple"]
The result above always contains a redundant trailing element, it should be shaved off afterwards:
iex(3) > with [_ | result] <- :lists.reverse([1, 2, "banana", 3, 4, "apple", 5, "apple"]) do
...(3)> :lists.reverse(result)
...(3)> end
#⇒ [1, 2, "banana", 3, 4, "banana", 5]
There isn't a built in function for this as far as I know, but this can be done using Enum.with_index and Enum.flat_map. When the remainder of the index and the second argument is the second argument minus 1, we insert the element + the callback into the resulting list, and just the element otherwise. I think it makes more sense that passing 1 as the every argument results in your example list instead of 2. You can simply change every with every - 1 if you want though.
defmodule A do
def insert_at_every(list, every, fun) do
list
|> Enum.with_index
|> Enum.flat_map(fn {x, i} ->
if rem(i, every) == every - 1 do
[x, fun.()]
else
[x]
end
end)
end
end
IO.inspect A.insert_at_every([1, 2, 3, 4, 5], 1, fn -> Enum.random(["apple", "banana"]) end)
IO.inspect A.insert_at_every([1, 2, 3, 4, 5], 2, fn -> Enum.random(["apple", "banana"]) end)
IO.inspect A.insert_at_every([1, 2, 3, 4, 5], 3, fn -> Enum.random(["apple", "banana"]) end)
Output:
[1, "apple", 2, "apple", 3, "banana", 4, "banana", 5, "apple"]
[1, 2, "apple", 3, 4, "apple", 5]
[1, 2, 3, "apple", 4, 5]

Why the map function doesn't return the list without duplicate elements?

I have this list:
list1 = [1, 1, 1, 3, 3, 3, 56, 6, 6, 6, 7]
And I wat to get rid of duplicate values. The code for the map function is taken from here.
this is the complete testing code:
list1 = [1, 1, 1, 3, 3, 3, 56, 6, 6, 6, 7]
list2 = []
map(lambda x: not x in list2 and list2.append(x), list1)
print(list2)
list2 = []
[list2.append(c) for c in list1 if c not in list2]
print(list2)
list2 = []
for c in list1:
if c not in list2:
list2.append(c)
print(list2)
In Python 2.7 is prints:
[1, 3, 56, 6, 7]
[1, 3, 56, 6, 7]
[1, 3, 56, 6, 7]
In Python 3.4 it prints:
[]
[1, 3, 56, 6, 7]
[1, 3, 56, 6, 7]
Why the map function returns an empty list in Python3?
Because in python-3.x a map is not evaluate immediately. It works as a generator where elements are generated on the fly by need: this can be more efficient since it is possible you for instance only need the first three elements so why would you calculate all elements? So as long as you do not materialize the output of map in a way, you have not really calculated the map.
You can for instance use list(..) to force Python to evaluate the list:
list(map(lambda x: not x in list2 and list2.append(x), list1))
In that case python-3.x will generate the same result for list2.

Haskell: How to show all elements in impair and pair indexes from a list?

It will need to get the next imput and output:
pospair [1, 3, 9, 2, 5, 7, 1, 11]
[1, 9, 5, 1]
posimpair [1, 3, 9, 2, 5, 7, 1, 11]
[3, 2, 7, 11]
This is the way to obtain the element on the specified index:
show_in_index::Ord a=>[a]->Int->a
show_in_index l n = l!!n
It shows a result like this:
*Main> show_in_index [1,4,2,7,9] 3
7
The most simple way to do this is using recursion:
pospair :: [a] -> [a]
pospair xs = aux xs [] True
where
aux [] acc _ = acc
aux (y:ys) acc True = aux ys (acc ++ [y]) False
aux (y:ys) acc False = aux ys acc True
Note how I use True or False value to keep track of what value to eliminate. If it's False, I don't include the value in acc (accumulator). If it's True, I include the value. Using the same idea, you can implement posimpair.
You could map the function for indexing
For pospair the following works:
map ([1, 3, 9, 2, 5, 7, 1, 11] !! ) [0,2..length [1, 3, 9, 2, 5, 7, 1, 11]-1]
For posimpair we only have to change the second list that is the one that holds the indexing numbers, previously we had the series of pairs and now we want the series of impairs, so instead of having 0,2,.. until the length of the list -1 we have to do it with 1,3,..until the length of the list-1.
map ([1, 3, 9, 2, 5, 7, 1, 11] !! ) [1,3..length [1, 3, 9, 2, 5, 7, 1, 11]-1]
The general implementation is
pospairs = map (list !!) [0,2..length list - 1]
posimpairs = map (list !!) [1,3..length list - 1]
I tested your example and works.

SML val 'a grupper = fn : int -> 'a list -> 'a list list

I wanna create a function that have the type int -> 'a list -> 'a list list
Function call:
grupper 2 [3, 1, 4, 1, 5, 9] shall return [[3, 1], [4, 1], [5, 9]]
grupper 4 [3, 1, 4, 1, 5, 9] shall return [[3, 1, 4, 1], [5, 9]]
grupper 42 [3, 1, 4, 1, 5, 9] shall return [[3, 1, 4, 1, 5, 9]].
I got this so far
fun grupper _ [] = []
| grupper n (x::xs) = if n > length(x::xs) then [x::xs]
else [List.take(x::xs, n)] # grupper (n) xs
some help please.
You should use both List.take and List.drop:
fun grupper _ [] = []
| grupper n xs = if n >= length xs then [xs]
else List.take(xs, n)::(grupper n (List.drop(xs, n)))