Hi im doing atomic kotlin manupulating lists exercise.I need to help understanding the following
val intRange = 1..3
intRange.map { a -> // [1]
intRange.map { b -> a to b }
} eq "[" +
"[(1, 1), (1, 2), (1, 3)], " +
"[(2, 1), (2, 2), (2, 3)], " +
"[(3, 1), (3, 2), (3, 3)]" +
"]"
where do a , b values come from ?
We have that val intRange = 1..3 :
This is an IntRange from 1 to 3 (both inclusive)
Then we have the first map: intRange.map { a -> ... }
This map is going to loop through the intRange and it takes a lambda function as a parameter which is this in your case { a -> ... }, a will take each time the value of the current Int from the IntRange, so this lambda function is going to get executed 3 times with a having 3 different values (1, 2, 3), and you can call that a anything else you want so your function could be like that for example:
intRange.map { myValue ->
println(myValue) // 1, 2, 3
}
and you can even delete myValue -> and the variable name will be it which is the default name:
intRange.map {
println(it) // 1, 2, 3
}
and the same thing for b, a and b are going to take their values from that intRange, they will start from 1 to 3 (1, 2, 3) because the intRange = 1..3, if you change it to this val intRange = 1..4, then a and b are going to start from 1 to 4.
Related
Whenever you want to create a frequency Map in Scala, you can easily call .groupBy on a collection.
val seq = Seq("a", "a", "b", "c", "b", "a")
seq.groupBy(a => a) // Map(b -> List(b, b), a -> List(a, a, a), c -> List(c))
Same is easily done with nested collections.
val nseq = Seq(Seq("a", 1), Seq("a", -1), Seq("b", -5), Seq("c", 100), Seq("b", 5), Seq("a", 0))
nseq.groupBy(a => a(0)) // Map(b -> List(List(b, -5), List(b, 5)), a -> List(List(a, 1), List(a, -1), List(a, 0)), c -> List(List(c, 100)))
Notice how values get aggregated together for each key.
I tried to find analogous function in D and found group. It works somewhat differently since it returns tuple pairs.
int[] arr = [1, 1, 2, 2, 3, 2, 2, 5];
arr.sort.group; // [Tuple!(int, uint)(1, 2), Tuple!(int, uint)(2, 4), Tuple!(int, uint)(3, 1), Tuple!(int, uint)(5, 1)]
arr.sort.group.assocArray; // [5:1, 3:1, 2:4, 1:2]
However, when it comes to nested collections.
Tuple!(string, int)[] arr = [tuple("a", 1), tuple("a", -1), tuple("b", 2), tuple("b", 25), tuple("c", 100), tuple("b", 21)];
arr.sort!("a[0] > b[0]").group!((a, b) => a[0] == b[0]); //(Tuple!(string, int)("c", 100), 1), (Tuple!(string, int)("b", 25), 3), (Tuple!(string, int)("a", 1), 2)]
The value aggregation does not happen and only the first value is taken. But what's the use of taking just one first value? One can of course circumvent this via
int[][string] res;
arr.each!(s => res[s[0]] ~= [s[1]]);
writeln(res) // ["c":[100], "a":[1, -1], "b":[25, 2, 21]]
but is it possible to this in one line without predefining res array?
Tuple!(string, int)[] arr = [tuple("a", 1), tuple("a", -1), tuple("b", 2), tuple("b", 25), tuple("c", 100), tuple("b", 21)];
arr.sort!("a[0] > b[0]").group!((a, b) => a[0] == b[0]); // [Tuple!(string, int)("b", 25):3, Tuple!(string, int)("c", 100):1, Tuple!(string, int)("a", 1):2]
That's not the result I'm getting:
https://run.dlang.io/is/9lVPkv
It results in [tuple(tuple("c", 100), 1), tuple(tuple("b", 25), 3), tuple(tuple("a", 1), 2)], which looks correct.
but is it possible to this in one line without predefining res array?
I think you're looking for chunkBy:
arr.sort!("a[0] > b[0]").chunkBy!((a, b) => a[0] == b[0]).each!writeln;
This results in:
[Tuple!(string, int)("c", 100)]
[Tuple!(string, int)("b", 25), Tuple!(string, int)("b", 2), Tuple!(string, int)("b", 21)]
[Tuple!(string, int)("a", 1), Tuple!(string, int)("a", -1)]
I'm supposed to return a list of tuples from an integer input.
For example:
output' 4 should return a list of tuples:
[(1, 1);
(2, 1); (2, 2);
(3, 1); (3, 2); (3, 3);
(4, 1); (4, 2); (4, 3); (4, 4)]
At the moment I'm getting
[(1, 1); (1, 2); (1, 3); (1, 4);
(2, 1); (2, 2); (2, 3); (2, 4);
(3, 1);(3, 2); (3, 3); (3, 4);
(4, 1); (4, 2); (4, 3); (4, 4)]
What I have so far:
let output' x =
let ls= [1..x]
ls |> List.collect (fun x ->[for i in ls -> x,i])
output' 4
I can't figure out how to get the needed output. Any help would be appreciated.
You can add a filter:
...
|> List.filter (fun (a, b) -> a >= b)`
or
let output x =
[ for i in 1..x do
for j in 1..i do yield (i,j)
]
In F# they mostly work with sequences, so here is a sequence-driven lazy solution:
let output' max =
let getTuples x =
seq { 1 .. x }
|> Seq.map (fun y -> (x, y))
seq { 1 .. max }
|> Seq.map getTuples
If you need lists, replace seq { 1 .. x } with [ 1 .. x ].
It will still be more functional-way than loops.
I have this list:
let myList = [(1,2,0);(1,3,0);(1,4,0);(2,6,0);(3,5,0);(4,6,0);(6,5,0);(6,7,0);(5,4,0)];;
I want to remove each element in list when the first position is equals with a number, for example if I remove the element starts with 1 the result must be this:
[(2,6,0);(3,5,0);(4,6,0);(6,5,0);(6,7,0);(5,4,0)];;
From OCaml's standard library:
val filter : ('a -> bool) -> 'a list -> 'a list
(** filter p l returns all the elements of the list l that satisfy
the predicate p. The order of the elements in the input list is
preserved. *)
The following function will compare a first element of a triple with a constant number n
let first_is n (m,_,_) = n = m
Then you can use this to filter your list:
List.filter (first_is 1) [1,2,3;4,5,6;7,8,9]
This will remove all elements that doesn't satisfy the predicate, i.e., in the given example it will return a list with only one triple: [1,2,3].
Since you want the opposite, then you can define predicate:
let first_isn't n (m,_,_) = n <> m
A full example in the interactive toplevel:
# let xs = [1,2,0;1,3,0;1,4,0;2,6,0;3,5,0;4,6,0;6,5,0;6,7,0;5,4,0];;
val xs : (int * int * int) list =
[(1, 2, 0); (1, 3, 0); (1, 4, 0); (2, 6, 0); (3, 5, 0); (4, 6, 0);
(6, 5, 0); (6, 7, 0); (5, 4, 0)]
# let first_isn't n (m,_,_) = n <> m;;
val first_isn't : 'a -> 'a * 'b * 'c -> bool = <fun>
# List.filter (first_isn't 1) xs;;
- : (int * int * int) list =
[(2, 6, 0); (3, 5, 0); (4, 6, 0); (6, 5, 0); (6, 7, 0); (5, 4, 0)]
E.g. for List(1, 1, 1, 2, 3, 3, 4) it would be Set(1, 3), because 1 and 3 are the only elements which occur multiple times.
val s = List(1, 1, 1, 2, 3, 3, 4) // a list with non-unique elements
(s diff s.distinct) toSet // Set(1, 3)
A bit more convoluted but you can avoid having to call toSet.toList, first group the integers:
scala> s.groupBy(identity)
res13: scala.collection.immutable.Map[Int,List[Int]] =
Map(2 -> List(2), 4 -> List(4), 1 -> List(1, 1, 1), 3 -> List(3, 3))
Then collect only the one were the list has length greater as 1:
scala> s.groupBy(identity).collect { case (v, l) if l.length > 1 => v }
res17: scala.collection.immutable.Iterable[Int] = List(1, 3)
If you want a Set just call toSet.
I'm brand new to Scala, having had very limited experience with functional programming through Haskell.
I'd like to try composing a list of all possible pairs constructed from a single input list. Example:
val nums = List[Int](1, 2, 3, 4, 5) // Create an input list
val pairs = composePairs(nums) // Function I'd like to create
// pairs == List[Int, Int]((1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 1) ... etc)
I tried using zip on each element with the whole list, hoping that it would duplicate the one item across the whole. It didn't work (only matched the first possible pair). I'm not sure how to repeat an element (Haskell does it with cycle and take I believe), and I've had trouble following the documentation on Scala.
This leaves me thinking that there's probably a more concise, functional way to get the results I want. Does anybody have a good solution?
How about this:
val pairs = for(x <- nums; y <- nums) yield (x, y)
For those of you who don't want duplicates:
val uniquePairs = for {
(x, idxX) <- nums.zipWithIndex
(y, idxY) <- nums.zipWithIndex
if idxX < idxY
} yield (x, y)
val nums = List(1,2,3,4,5)
uniquePairs: List[(Int, Int)] = List((1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5), (3, 4), (3, 5), (4, 5))
Here's another version using map and flatten
val pairs = nums.flatMap(x => nums.map(y => (x,y)))
List[(Int, Int)] = List((1,1), (1,2), (1,3), (1,4), (1,5), (2,1), (2,2), (2,3), (2,4), (2,5), (3,1), (3,2), (3,3), (3,4), (3,5), (4,1), (4,2), (4,3), (4,4), (4,5), (5,1), (5,2) (5,3), (5,4), (5,5))
This can then be easily wrapped into a composePairs function if you like:
def composePairs(nums: Seq[Int]) =
nums.flatMap(x => nums.map(y => (x,y)))