For example, if I have a list like this:
[("pizza", 4); ("milkshake", 2); ("chocolate", 2); ("pizza", 3); ("milkshake", 3); ("pizza", 4)]
and I want to sum all the second elements of the tuples while the first tuple is the same. How should I do it?
The output should be:
[("pizza", 11); ("milkshake", 5); ("chocolate, 2")]
You can used List.groupBy to group the items according to the item name:
let items = [("pizza", 4); ("milkshake", 2); ("chocolate", 2); ("pizza", 3); ("milkshake", 3); ("pizza", 4)]
let grouped = List.groupBy fst items
// returns the following:
// [("pizza", [("pizza", 4); ("pizza", 3); ("pizza", 4)]);
// ("milkshake", [("milkshake", 2); ("milkshake", 3)]);
// ("chocolate", [("chocolate", 2)])]
This returns a list of tuples where the first entry is the item name (e.g. pizza) and the second entry is itself a list, containing all the original tuples which match that name.
Then you can map each sub-list to the sum of the second entries:
let summed = List.map (fun (name, entries) -> (name, entries |> List.sumBy snd)) grouped
// returns [("pizza", 11); ("milkshake", 5); ("chocolate", 2)] as expected
The documentation for the List module shows all the built in functions for working with lists.
Note that fst and snd are built-in functions which return the first and second elements of a two-element tuple respectively.
Once you're more familiar with F#, you might want to use the forward pipe operator |> to do this more succinctly:
let summed =
items
|> List.groupBy fst
|> List.map (fun (name, entries) -> (name, entries |> List.sumBy snd))
Related
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 complete the activity at the bottom of this page, where I need to print the index of each element as well as the value. I'm starting from the code
use std::fmt; // Import the `fmt` module.
// Define a structure named `List` containing a `Vec`.
struct List(Vec<i32>);
impl fmt::Display for List {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Extract the value using tuple indexing
// and create a reference to `vec`.
let vec = &self.0;
write!(f, "[")?;
// Iterate over `vec` in `v` while enumerating the iteration
// count in `count`.
for (count, v) in vec.iter().enumerate() {
// For every element except the first, add a comma.
// Use the ? operator, or try!, to return on errors.
if count != 0 { write!(f, ", ")?; }
write!(f, "{}", v)?;
}
// Close the opened bracket and return a fmt::Result value
write!(f, "]")
}
}
fn main() {
let v = List(vec![1, 2, 3]);
println!("{}", v);
}
I'm brand new to coding and I'm learning Rust by working my way through the Rust docs and Rust by Example. I'm totally stuck on this.
In the book you can see this line:
for (count, v) in vec.iter().enumerate()
If you look at the documentation, you can see a lot of useful functions for Iterator and enumerate's description states:
Creates an iterator which gives the current iteration count as well as the next value.
The iterator returned yields pairs (i, val), where i is the current index of iteration and val is the value returned by the iterator.
enumerate() keeps its count as a usize. If you want to count by a different sized integer, the zip function provides similar functionality.
With this, you have the index of each element in your vector. The simple way to do what you want is to use count:
write!(f, "{}: {}", count, v)?;
This is a simple example to print the index and value of a vector:
fn main() {
let vec1 = vec![1, 2, 3, 4, 5];
println!("length is {}", vec1.len());
for x in 0..vec1.len() {
println!("{} {}", x, vec1[x]);
}
}
This program output is -
length is 5
0 1
1 2
2 3
3 4
4 5
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
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.
Is there a standard library function or built-in construct to concatenate two sequences in JavaFX?
Here a Sequences.concatenate() function is mentioned, but it is nowhere to be seen in the official API.
Of course one could iterate over each sequence, inserting the values into a new sequence e.g:
function concatenate(seqA: Object[], seqB: Object[]) : Object[] {
for(b in seqB) insert b into seqA;
seqA;
}
..but surely something as basic as concatenation is already defined for us somewhere..
It is very simple, since there cannot be sequence in sequence (it all gets flattened), you can do it like this:
var a = [1, 2];
var b = [3, 4];
// just insert one into another
insert b into a;
// a == [1, 2, 3, 4];
// or create a new seq
a = [b, a];
// a == [3, 4, 1, 2];
Hope that helps.