Given a sequence of items as follows:
[ ("a", 1); ("a", 2); ("a", 3); ("b", 1); ("c", 2); ("c", 3) ]
How can I convert this lazily into:
{ ("a", { 1; 2; 3}); ("b", { 1 }); ("c", { 2; 3}) }
You can assume that the input data source is already sorted on the grouping key element e.g. "a" "b" and "c".
I'm using the { } there to indicate that it's a lazily-evaluated sequence of items.
I've gotten it working imperatively with two while loops operating over the IEnumerator of the source sequence, but this involves creating reference variables and mutation etc. etc. I'm sure that there are better ways of doing this, perhaps with Recursion or using some of the operations in the Seq library e.g. scan or unfold?
If you want to implement this over IEnumerable<'T> (to make it lazy), then it is necessarily going to be somewhat imperative, because the IEnumerator<'T> type that is used to iterate over the input is imperative. But the rest can be written as a recursive function using sequence expressions.
The following is lazy in the first level (it produces each group lazily), but it does not produce elements of the group lazily (I think that would have pretty subtle semantics):
/// Group adjacent elements of 'input' according to the
/// keys produced by the key selector function 'f'
let groupAdjacent f (input:seq<_>) = seq {
use en = input.GetEnumerator()
// Iterate over elements and keep the key of the current group
// together with all the elements belonging to the group so far
let rec loop key acc = seq {
if en.MoveNext() then
let nkey = f en.Current
if nkey = key then
// If the key matches, append to the group so far
yield! loop key (en.Current::acc)
else
// Otherwise, produce the group collected so far & start a new one
yield List.rev acc
yield! loop nkey [en.Current]
else
// At the end of the sequence, produce the last group
yield List.rev acc
}
// Start with the first key & first value as the accumulator
if en.MoveNext() then
yield! loop (f en.Current) [en.Current] }
Unfortunately, this (pretty useful!) function is not included in the standard F# library, so if you want to group adjacent elements (rather than arbitrary elements in the list using Seq.groupBy), you have to define it yourself...
let p = [("a", 1); ("a", 2); ("a", 3); ("b", 1); ("c", 2); ("c", 3)]
let l = p |> Seq.groupBy fst |> Seq.map(fun x -> fst x, snd x |> Seq.map snd)
In F#+ there is a generic function chunkBy that can be used to do that:
#r "FSharpPlus.dll"
open FSharpPlus
seq [ ("a", 1); ("a", 2); ("a", 3); ("b", 1); ("c", 2); ("c", 3) ]
|> chunkBy fst
|> map (fun (x,y) -> x, map snd y)
And it works with seq, array and list.
The implementation for seq is pretty much the same as the groupdAdjacent from Tomas.
Seq.groupBy fst
Will do the trick
Related
I'm learning Elixir and I'm having a difficulty with this simple problem:
I have a list of values:
my_list = ["a", "b", "c", "y", "z", "a", "e"]
And I have a map:
my_map = %{"a" => -1, "b" => 0, "c" => 1, "d" => 2, "e" => 3}
I want to loop through my_list, find all key occurrences in my_map and sum the values from my_map if the occurrence happened.
In the above example it should return 2 because:
-1 + 0 + 1 + (ignored) + (ignored) - 1 + 3
# => 2
This is a very easy thing to do in languages with mutable variables (we can loop the list and add a counter). I'm working on changing my mindset.
Thank you for help!
I'm working on changing my mindset.
Admirable. You'll find great success in Elixir if you're willing to change your mindset and try to think more functionally. With that in mind, let's break the problem down.
I want to loop through my_list
More precisely, you want to do something to each element of the list and get a list of the results. That's Enum.map/2.
Enum.map(my_list, fn x -> ...)
Now, ... needs to be replaced with what we want to do to each list element. We want to get the corresponding map elements, ignoring those that are not present. Since we're taking a sum, "ignoring" really just means "replacing with zero". Map.get/3 can get a value from a map, using a default if not provided.
Enum.map(my_list, fn x -> Map.get(my_map, x, 0) end)
Now, we have a list of numbers. We just want the sum. That could be done in terms of Enum.reduce/3, but summing is a common enough task that it has its own function: Enum.sum/1.
Enum.sum(Enum.map(my_list, fn x -> Map.get(my_map, x, 0) end))
Finally, this reads backwards. It says "sum the result of mapping over the list", when it would read much cleaner as "take the list, get the elements from the map, then take a sum". We can clean it up with the pipe operator. The following is equivalent to the above.
my_list |> Enum.map(fn x -> Map.get(my_map, x, 0) end) |> Enum.sum
This is a nice use case for a comprehension:
for key <- my_list, val = my_map[key], reduce: 0 do
acc -> acc + val
end
Here the val = my_map[key] is a filter. When key is not in my_map, the result will be nil, which is a falsy value so is skipped.
While both answers given here are perfectly valid, I’m to post another one using plain recursion, for the sake of completeness.
defmodule Summer do
def consume(list, map, acc \\ 0) # head
def consume([], _, acc), do: acc # exhausted
def consume([h | t], map, acc) when is_map_key(map, h),
do: consume(t, map, acc + Map.fetch!(map, h))
def consume([_h | t], map, acc), do: consume(t, map, acc)
end
Summer.consume my_list, my_map
#⇒ 2
I'm a beginner in functional programming but I'm famaliar with imperative programming. I'm having trouble translating a piece of cpp code involving updatating two objects at the same time (context is n-body simulation).
It's roughly like this in c++:
for (Particle &i: particles) {
for (Particle &j: particles) {
collide(i, j) // function that mutates particles i and j
}
}
I'm translating this to Ocaml, with immutable objects and immutable Lists. The difficult part is that I need to replace two objects at the same time. So far I have this:
List.map (fun i ->
List.map (fun j ->
let (new_i, new_j) = collide(i, j) in // function that returns new particles i, j
// how do i update particles with new i, j?
) particles
) particles
How do I replace both objects in the List at the same time?
The functional equivalent of the imperative code is just as simple as,
let nbody f xs =
List.map (fun x -> List.fold_left f x xs) xs
It is a bit more generic, as a I abstracted the collide function and made it a parameter. The function f takes two bodies and returns the state of the first body as affected by the second body. For example, we can implement the following symbolic collide function,
let symbolic x y = "f(" ^ x ^ "," ^ y ^ ")"
so that we can see the result and associativity of the the collide function application,
# nbody symbolic [
"x"; "y"; "z"
];;
- : string list =
["f(f(f(x,x),y),z)"; "f(f(f(y,x),y),z)"; "f(f(f(z,x),y),z)"]
So, the first element of the output list is the result of collision of x with x itself, then with y, then with z. The second element is the result of collision of y with x, and y, and z. And so on.
Obviously the body shall not collide with itself, but this could be easily fixed by either modifying the collide function or by filtering the input list to List.fold and removing the currently being computed element. This is left as an exercise.
List.map returns a new list. The function you supply to List.map may transform the elements from one type to another or just apply some operation on the same type.
For example, let's assume you start with a list of integer tuples
let int_tuples = [(1, 3); (4, 3); (8, 2)];;
and let's assume that your update function takes an integer tuple and doubles the integers:
let update (i, j) = (i * 2, j * 2) (* update maybe your collide function *)
If you now do:
let new_int_tuples = List.map update int_tuples
You'll get
(* [(2, 6); (8, 6); (16, 4)] *)
Hope this helps
Having trouble with a problem:
Define a function called zip that takes a pair (tuple) of equal length lists as a single parameter and returns a list of pairs. The first pair should contain the first element of each list, the second pair contains the second element of each list, and so on.
I have been stuck and am looking for advice on if I'm headed in the right direction or should try another approach.
It needs to be a single function definition without any nested functions and can not use build in functions!
What I have done is:
let rec zip (a , b) =
if List.length a = 1 then List.head a , List.head b
else zip (List.tail a , List.tail b)
when
> zip (["a"; "b"; "c"; "d"; "e"], [1; 2; 3; 4; 5]);;
is entered
val it : string * int = ("e", 5)
is returned.
The expected result should be
val it : (string * int) list = [("a", 1); ("b", 2); ("c", 3); ("d", 4); ("e", 5)]
Let's start with your original implementation:
let rec zip (a , b) =
if List.length a = 1 then List.head a , List.head b
else zip (List.tail a , List.tail b)
First of all, the type is wrong - this returns a tuple of values, not a list of tuples. What this does is that it iterates over the list (following the tails using List.tail) and when it reaches the end, it returns the only element of each of the lists, which is "e" and 5.
The first step to fixing this could be to add type annotations. This will force you to return a list in the then branch. If you have two singleton lists ["e"] and [5], you want to return ["e", 5]:
let rec zip (a:'a list , b:'b list) : list<'a * 'b> =
if List.length a = 1 then [List.head a , List.head b]
else zip (List.tail a , List.tail b)
This is still not right - in the else case, you are just looking at the tails, but you are ignoring the heads. You need to access the head and concatenate it to the list returned from your recursive call:
let rec zip (a:'a list , b:'b list) : list<'a * 'b> =
if List.length a = 1 then [List.head a , List.head b]
else (List.head a, List.head b) :: zip (List.tail a , List.tail b)
This works, but using if .. then .. else in this case is inelegant. The answer from Filipe shows how to do this better with pattern matching.
let rec zip (a, b) =
match (a, b) with
| ha :: ta, hb :: tb -> (ha, hb) :: zip (ta, tb)
| _, _ -> []
I'm trying to write some code in a functional paradigm for practice. There is one case I'm having some problems wrapping my head around. I am trying to create an array of 5 unique integers from 1, 100. I have been able to solve this without using functional programming:
let uniqueArray = [];
while (uniqueArray.length< 5) {
const newNumber = getRandom1to100();
if (uniqueArray.indexOf(newNumber) < 0) {
uniqueArray.push(newNumber)
}
}
I have access to lodash so I can use that. I was thinking along the lines of:
const uniqueArray = [
getRandom1to100(),
getRandom1to100(),
getRandom1to100(),
getRandom1to100(),
getRandom1to100()
].map((currentVal, index, array) => {
return array.indexOf(currentVal) > -1 ? getRandom1to100 : currentVal;
});
But this obviously wouldn't work because it will always return true because the index is going to be in the array (with more work I could remove that defect) but more importantly it doesn't check for a second time that all values are unique. However, I'm not quite sure how to functionaly mimic a while loop.
Here's an example in OCaml, the key point is that you use accumulators and recursion.
let make () =
Random.self_init ();
let rec make_list prev current max accum =
let number = Random.int 100 in
if current = max then accum
else begin
if number <> prev
then (number + prev) :: make_list number (current + 1) max accum
else accum
end
in
make_list 0 0 5 [] |> Array.of_list
This won't guarantee that the array will be unique, since its only checking by the previous. You could fix that by hiding a hashtable in the closure between make and make_list and doing a constant time lookup.
Here is a stream-based Python approach.
Python's version of a lazy stream is a generator. They can be produced in various ways, including by something which looks like a function definition but uses the key word yield rather than return. For example:
import random
def randNums(a,b):
while True:
yield random.randint(a,b)
Normally generators are used in for-loops but this last generator has an infinite loop hence would hang if you try to iterate over it. Instead, you can use the built-in function next() to get the next item in the string. It is convenient to write a function which works something like Haskell's take:
def take(n,stream):
items = []
for i in range(n):
try:
items.append(next(stream))
except StopIteration:
return items
return items
In Python StopIteration is raised when a generator is exhausted. If this happens before n items, this code just returns however much has been generated, so perhaps I should call it takeAtMost. If you ditch the error-handling then it will crash if there are not enough items -- which maybe you want. In any event, this is used like:
>>> s = randNums(1,10)
>>> take(5,s)
[6, 6, 8, 7, 2]
of course, this allows for repeats.
To make things unique (and to do so in a functional way) we can write a function which takes a stream as input and returns a stream consisting of unique items as output:
def unique(stream):
def f(s):
items = set()
while True:
try:
x = next(s)
if not x in items:
items.add(x)
yield x
except StopIteration:
raise StopIteration
return f(stream)
this creates an stream in a closure that contains a set which can keep track of items that have been seen, only yielding items which are unique. Here I am passing on any StopIteration exception. If the underlying generator has no more elements then there are no more unique elements. I am not 100% sure if I need to explicitly pass on the exception -- (it might happen automatically) but it seems clean to do so.
Used like this:
>>> take(5,unique(randNums(1,10)))
[7, 2, 5, 1, 6]
take(10,unique(randNums(1,10))) will yield a random permutation of 1-10. take(11,unique(randNums(1,10))) will never terminate.
This is a very good question. It's actually quite common. It's even sometimes asked as an interview question.
Here's my solution to generating 5 integers from 0 to 100.
let rec take lst n =
if n = 0 then []
else
match lst with
| [] -> []
| x :: xs -> x :: take xs (n-1)
let shuffle d =
let nd = List.map (fun c -> (Random.bits (), c)) d in
let sond = List.sort compare nd in
List.map snd sond
let rec range a b =
if a >= b then []
else a :: range (a+1) b;;
let _ =
print_endline
(String.concat "\t" ("5 random integers:" :: List.map string_of_int (take (shuffle (range 0 101)) 5)))
How's this:
const addUnique = (ar) => {
const el = getRandom1to100();
return ar.includes(el) ? ar : ar.concat([el])
}
const uniqueArray = (numberOfElements, baseArray) => {
if (numberOfElements < baseArray.length) throw 'invalid input'
return baseArray.length === numberOfElements ? baseArray : uniqueArray(numberOfElements, addUnique(baseArray))
}
const myArray = uniqueArray(5, [])
In F# is there a way to map for example [2;2;2;2;5;5;5;7;7] to [4,3,2] without recursion and without mutable? I looked through the Array and List members and found Reduce but that does not seem to help.
You can implement it quickly using Seq.countBy. Using F# interactive, it looks like this:
> [2;2;2;2;5;5;5;7;7] |> Seq.countBy id;;
val it : seq<int * int> = seq [(2, 4); (5, 3); (7, 2)]
If you only want the counts (and not the values which were repeated), you can just pipe the result into Seq.map:
> [2;2;2;2;5;5;5;7;7] |> Seq.countBy id |> Seq.map snd;;
val it : seq<int> = seq [4; 3; 2]
Note that you can implement this using Seq.groupBy, but Seq.countBy is much more efficient: Seq.groupBy consumes more memory because it has to store all of the groups, whereas Seq.countBy stores just one int (the counter) for each key in the sequence.
Try this:
[2;2;2;2;5;5;5;7;7] |> Seq.groupBy id |> Seq.map (snd >> Seq.length)
Seq.groupBy id collects the list up into groups of equal elements - using the identity function id means that the elements of the sequence are used directly as the "keys" for the equality check. This gives us a sequence of the original elements paired up with the repeats:
seq [(2, seq [2; 2; 2; 2]); (5, seq [5; 5; 5]); (7, seq [7; 7])]
Then for each of the inner sequences, we use snd to just get the sequence of repeats, and Seq.length to get its length. >> is the composition operator that applies the first function and then the second.