I am starting to get into Scala for an assignment, and I've been looking for how to add an Item to a List in for about an hour now. I have found several solutions of course, and the code snipped below DOES compile, BUT the produced list is just empty. Can anyone tell me why that is?
case NodeList(ls) => {
var ls0 = List()
ls.foreach {
println("hey") // => printed 3 times
i => ls0 :+ i
}
println(ls0) // => Empty list as output (ls contains 3 items when called)
}
Would appreciate help alot! Thanks in advance.
You are appending an item to the list, but you never store the resulting new list. Basically, you append an item, then throw away the result, append again, throw away again, and so on.
You need to store the list somewhere.
Note that appending to a list is a bad idea: you have to iterate over the entire list to find the last element, then the next time you append, you have to do it again, and again, and again. That means your code has an algorithmic complexity of (n^2 - n)/2, when the same could be easily done in Θ(n). You should always prepend to a list, never append.
Related
I going through some Scala exercises in order to understand better high order functions. I have the following problem, which I cant understand how to solve. I have the following list:
val input = List((1,"a"), (1,"b"), (1,"c"), (2,"d"), (2,"y"), (2,"e"), (3, "u"), (3,"a"), (3,"d"))
I want to create a Map from this list which maps each letter encountered on the input list to a list of all the numbers which were previously in the same tuple as that letter. Example output:
Map(a -> List(1,3), b->List(1), c->List(1), d->List(2,3), y->List(2), e->List(2), u->List(3)
What I have tried so far is:
val output = input.groupBy(_._2)
However this gives as output:
Map(e -> List((2,e)), y -> List((2,y)), u -> List((3,u)), a -> List((1,a), (3,a)), b -> List((1,b)), c -> List((1,c)), d -> List((2,d), (3,d)))
Could someone help me understand how I could go about solving this? I appreciate any help as I am new to functional programming
As #sinanspd said:
input
.groupBy {
case (numer, letter) => letter
} map {
case (key, list) => key -> list.map {
case (number, letter) => number
}
}
// Or equivalently
input.groupBy(_._2).view.mapValues(list => list.map(_._1)).toMap
// Or even simpler if you have access to Scala 2.13
input.groupMap(_._2)(_._1)
Every time you want to transform some collection of values where the transformation is one to one, you just need a map, so in this case, you want to transform the values of the Map returned by the groupBy, which are Lists, and then you want to transform every element of those Lists to just return the first component of the tuple. So it is a map inside another map.
Also, the Scaldoc is your friend. Usually, there are many useful methods, like mapValues or groupMap.
Here is a more detailed explanation of my comment. This is what you need to do:
val output = input.groupBy(_._2).mapValues(_.map(_._1))
It is important to remember in functional programming we love pure functions. Meaning we will not have shady side effects and we like to stick to one function one purpose principle
This allows us to chain these pure functions and reason about them linearly. Why am I telling you this? While your instinct might be to look for or implement a single function to do this, don't
In this case, we first groupBy the key, and then map each value where we take the value List and map it to extract the _._1 of the tuple.
This is the best I could do, to make it sorted too , as I see the other responses are not sorted , maybe someone can improve this too:
import scala.collection.immutable.ListMap
ListMap(input.groupBy(_._2).mapValues(_.map(_._1)).toSeq.sortBy(_._1):_*)
I have been trying to do a function that returns to me the first (or all it might work to but I do prefer just the first), element of a list of lists that is single, i mean:
[[x;y;z];[a;b;c];[a];[b]]
In this case I would like to get returned the a or [a] but I cant I tried to do a function something like:
let rec find_unit ll =
match ll with
| [x] -> [x]
and so on...
But every time I try something like this, I get in a recursion that never stops, or the function simple dont return the element. Can someone tell me how to do it properly? I still cant understand a lot of OCaml syntax... Just like in the example I dont know that to put in the line of |[x] -> [x], particularly the first [x].
Sorry for the question but I am destroying my code now and I cant find a solution.
Try decomposing your problem into smaller subproblems.
(1) Your problem overall looks like an instance of the more general 'find'-problem, which has already been solved. See the standard function List.find or (if you want to find them all... List.find_all. Both functions need a predicate to pick the right element(s) from the list.
(2) You need a way to determine if some list is a singleton. It's easy, use pattern-mathing.
let is_singleton xs = function
| [_] -> true
| _ -> false
(3) Now, combine the above and you'll get a solution.
A couple of observations on the code you give:
Your pattern needs to match the whole string ll, but the pattern you give seems to be intended to match just one element of ll. A pattern more like [x] :: rest is going to work better.
The way to avoid infinite recursion is always the same. First, make sure you check for the smallest possible input (the basis). For your problem this will be the case when ll is an empty list. Second, if you haven't found what you're looking for, continue the search on a smaller problem. In your case this will mean searching the tail of your list.
You also need to decide what to do when there is no element of the list like the one you're looking for. If you return [x] when you find it, you could return [] (say) if you don't find it. Or you could raise an exception like Not_found.
(As a side comment, lists and arrays are different things in OCaml. I removed the array tag, as your question seems to be about lists.)
Well all answers here helped me find a way to get the solution, and I am going to put it here because it might help someone else.
I used the function:
let is_single xs = function
| [_] -> true
| _ -> false
to do: let teste xs = List.filter(fun inner ->(is_single inner)inner)xs;; This teste function is returning to me a List of Lists with all single elements, so to get only one element inside of that lists i did: List.hd(List.hd teste xs)
I am a newbie to prolog, till now I am able to read all words of file, displayed them one by one, now I want to store them in a list(one by one, as I soon as I am displaying them). All logic for append given everywhere, append content of two lists in an empty list. For example
append(new_word,word_list,word_List), intially my word_list is empty, so everything fine, but afterwards it says no, and stop at that point.
Need help to be able to store element in list one by one.
You can use difference lists :
file_to_list(W, L) :-
read_word(Word),
append_dl(W, [Word|U]-U, Ws),
!, file_to_list(Ws, L).
file_to_list_1(Ws, Ws).
append_dl(X-Y, Y-Z, X-Z).
You call file_to_list(U-U, L-[]) to get the list of words. There is no slowdown but takes more inferences than CapelliC's code (one per word).
I'm having a hard time wrapping my head around the concept of logic programming. I'm trying to get all permutations with repetition into a give list.
I can put what I have, but I don't know what I'm doing!
perms_R(List,[]).
perms_R([X|Xt],[Y|Yt],Out) :- perms_R([Y|Xt],Yt),perms_R(Xt,[Y|Yt])
.
The idea was to go through each element in the second list and put it in my first list. I'm trying to figure this out, but I'm stuck.
I need to call perms_R([a,b,c,d],[1,2,3,4]). and get:
1,1,1,1
1,1,1,2
1,1,1,3
1,1,1,4
1,1,2,1
etc....
I understand the first list seems useless and I could just do it with a list length, but I actually need it for the remainder of my code, so I'm trying to model this after what I need. Once I get past this part, I will be putting extra logic in that will limit the letters that can be replaced in the first list, but don't worry about that part!
What you are looking for is not a permutation. You want to create a list of a given size using items from a given set.
You may do it with this snippet:
perms_R([], _).
perms_R([Item|NList], List):-
member(Item, List),
perms_R(NList, List).
You would need to pass a semi instantiated list and the source items:
perms_R([A,B,C,D],[1,2,3,4]).
I need to build a new list with a "loop". Basically i can't use recursion explicitly, so i am using append to go through lists of list.
I can get the element. Problem is i need to check this element and if something is true it returns another element i need to put back into the list. It does check correctly and it changes correctly.
Problem i am having is how do i create a completely new list.
So, if i had
[[1,1,1],[2,6,2],[3,3,3]]
I go through each element. say i get to the 6 and it changes. So i need to create a new list like so,
[[1,1,1],[2,10,2],[3,3,3]].
Right now my main problem is just creating each row. If i can create each row, i will be able to create a list of lists.
So to break this down a little more, lets just worry about [1,1,1].
I go through each element while appending the new element to a newlist. the new list is now [1,1,1]
I have this:
set(Row,Col,Bin,TheEntry,Bout) :-
append(ListLeft, [R|_], Bin),
append(ListLeft2, [C|_], R),
length(ListLeft, LenR),
length(ListLeft2,LenC),
CurrRow is LenR + 1,
CurrCol is LenC + 1,
getChar(C, Row, Col, CurrRow, CurrCol,TheEntry, NewC),
appendhere?.
I need to create a new list there with the character returned from NewC. Not sure how to do this.
Any clues?
Thanks.
To give you an idea about how to use append/3 to extract an item from a list of lists, consider the following predicate called replace/2:
replace(In, Out) :-
append(LL, [L|RL], In),
append(LE, [E|RE], L),
replaceElement(E, NewE), !,
append(LE, [NewE|RE], NewL),
append(LL, [NewL|RL], Out).
replace(In, In).
This non-recursive predicate takes, as Input, a list of lists, and backtracks to find an element E within an inner list L that can be replaced via replaceElement/2; if so, it is replaced by constructing the inner list first (NewL), then uses this new list in the construction of the new outer list (Out), as the result.
Note that this simply serves to demonstrate how to use append/3 to break apart a list of lists to retrieve individual elements as you need via backtracking, and not recursion, as requested. Once an element E is found to be replaceable by NewE via replaceElement/3, it is used in the construction of the list again using append/3 as shown.
Also note that this suggestion (which is intended to help you, not be your final answer) also happens to replace only a single element within an inner list, if any at all. If you want to do multiple replacements of the input list in a single call to replace/2 or similar using this technique, then you will almost certainly need a recursive definition, or the ability to use the global database via assert. I'm happy to be corrected if someone else can provide a definition as a counterexample.
With this example predicate replace/2, together with, say, the following fact:
replaceElement(6, 10).
Executing the following gives us your required behaviour:
1 ?- replace([[1,1,1],[2,6,2],[3,3,3]], Out).
Out = [[1, 1, 1], [2, 10, 2], [3, 3, 3]] ;
false.
If you cannot use cut (!), it is fine to omit it, but note that the second clause replace(In, In) will cause all calls to replace/2 to backtrack at least once to give you the input list back. If this behaviour is undesirable, omitting this second clause will cause replace/2 to fail outright if there is no replacement to be made.
If you cannot use recursion and have to do it with backtracking you should do something like this:
Assume Bin is a list of lists (each item is a full row)
~ Split input Bin in three parts (a list of 'left' rows, a Row, and a list of remaining rows). This can be done using append/3 with something like append(Left, [Item|Rest], Rows)
~ Now obtain the length of the 'left' rows
~ Test the length using 'is' operator to check wether the left list has Row - 1 items
~ Do the same but now with the Item, i.e. split it in three parts (LeftColums, ColumItem and Rest)
~ Test now the length against the required Column
~ Now you have the Item to change so all you need to do is rebuild a list using two appends (one to rebuild the chosen row and another to rebuild the output list).
So from your code you wouldn't use unnamed variables (_). Instead of that you have to use a named variable to be able to rebuild the new list with the item changed.