Related
I have a list of tuples in the following format
[{"string1",1},{"string2",2}...]
I'm gonna use that for another function but i realized i can't have that or rather i just think is too difficult to operate over that list in that format, so my solution was transforming that list into the following
["string1", "string2",...]
But i'm not sure how to do this as i'm still learning how Elixir works.
My way of getting it was this:
for x <- words do
text ++ elem(words,0)
end
"text" being an empty list and "words" being the list of tuples. But of course this doesn't work, not really sure why.
If you want to do it using for, you need to understand that for is not a construct to iterate over things, as in other programming languages. In Elixir, for is used for comprehensions, meaning that the result will be a data structure, created from an enumerable, like your list of tuples.
You also need to understand that if you updated your code, text ++ elem(words, 0) wouldn't actually update text, and that ++ doesn't work the way you think it does either. ++ is useful for concatenating lists, or keyword lists, but not for adding single elements to a list. For that purpose you could do list ++ ["string"] or ["string"] ++ list which is faster; or even simpler: ["string" | list].
And the reason it wouldn't update your list, is that in each "iteration" you would just be producing the concatenation, but you wouldn't actually be assigning that anywhere. And things in Elixir are not mutable, so ++ doesn't actually update something
Now, in order to correctly create what you want using for, you could do it like this:
iex> list = [{"string1", 1}, {"string2", 2}]
[{"string1", 1}, {"string2", 2}]
iex> for tup <- list, do: elem(tup, 0)
["string1", "string2"]
iex> for {string, _} <- list, do: string
["string1", "string2"]
Which basically means: using this list, create a new one, keeping only the first element of each tuple. Since a list is the default output of for. But you could also change the resulting data structure adding into: %{} or something else. Comprehensions are very powerful, you can get a better understanding of them here
Another popular way to solve it would be using Enum.map, which maps a given enumerable to something else. Meaning that it transforms the elements of the enumerable, so you could do it like this as well:
iex> list = [{"string1", 1}, {"string2", 2}]
[{"string1", 1}, {"string2", 2}]
iex> Enum.map(list, fn {string, _} -> string end)
["string1", "string2"]
Here, the transformation would be made by the function which takes the tuple, matching the first element into something called string and "returns" just that for each element.
Another simple way you could to it is using Enum.unzip/1 which takes a list of two-element tuples, like the ones you have, and produces a tuple with two elements. The first one being a list with the first element from each of your tuples, and the second one, a list with the second element from each of your tuples.
So, you could do:
iex> list = [{"string1",1},{"string2",2}]
[{"string1", 1}, {"string2", 2}]
iex> {strings, _} = Enum.unzip(list)
{["string1", "string2"], [1, 2]}
iex> strings
["string1", "string2"]
This way, you would be left with a strings variable, containing the list you want. However, this only works with two element tuples, so if you have any tuple that has more than two, it wouldn't work. Besides, you wouldn't be using the second list, so the for comprehension here could suit you better.
The most simple way to solve this is just using Enum.map https://hexdocs.pm/elixir/Enum.html#map/2
[{"string1", 1}, {"string2", 2}]
|> Enum.map(fn { string, _ } -> string)
To learn Elixir just keep doing what you are doing and look into the Docs and keep asking here as well
I have a list containing lists and I want to reverse every second list in it. I tried something but if I have odd number of elements in the list the last list element is lost... So the best solution would be to put the odd lists first and the even lists second till every second list is reversed.
I can't use any libraries. I need to do it recursively or split them and append them again. The best thing I made so far was to reverse only the first even list and append the first odd and even list in a new list.
I tried to do this:
reverselist(List, [List]).
reverselist([X,Y|Rest], [SnakeList|Rest2]):-
append(X, [], Odd),
reverse(Y, EvenList),
append(Odd, EvenList, SnakeList),
reverselist(Rest, Rest2).
And this:
reverselist(List1, List2).
reverselist([H|Ts], [Odd|R]):-
not(0 is H mod 2),
append(H, [], Odd),
reverselist(Ts, R).
reverselist([H|Ts], [Even|R]):-
0 is H mod 2,
reverse(H, Even),
reverselist(Ts, R).
Sample query:
?- reverselist([[a,b,c],[d,a,b],[c,d,o],[b,c,d],[e,e,d]], List).
I want the result to be:
List = [ [a,b,c],[b,a,d],[c,d,o],[d,c,b],[e,e,d] ].
You can also write mutual recursion:
reverselist([],[]).
reverselist([H|T],[H|T1]):-reverselist2(T,T1).
reverselist2([],[]).
reverselist2([H|T],[H1|T1]):-reverse(H,H1), reverselist(T,T1).
You were pretty close with your first variant.
Instead of your
reverselist(List, [List]).
reverselist([X,Y|Rest], [SnakeList|Rest2]):-
append(X, [], Odd),
reverse(Y, EvenList),
append(Odd, EvenList, SnakeList),
reverselist(Rest, Rest2).
just tweak it as
reverselist([], []). % additional clause
reverselist([List], [List]).
reverselist([X,Y|Rest], [X,EvenList|Rest2]):-
reverse( Y, EvenList),
reverselist( Rest, Rest2).
All three clauses are mutually exclusive and together they are exhaustive, i.e. they cover every possibility.
I believe this definition to be the most immediate and close representation of your problem. In Prolog, to formulate the problem means to have the solution for it.
We need to create another predicate with one more argument to keep track of odd or even position:
reverselist(InList,OutList):- reverselist(InList,OutList, 0).
reverselist([],[],_). %base case
%case of even position
reverselist([H|T],[H|T1], 0):- reverselist(T,T1,1).
%case of odd position
reverselist([H|T],[H1|T1], 1):- reverse(H1,H), reverselist(T,T1,0).
I need to create a list from a knowledgebase that could look like this:
fact1(3,3).
fact1(2,3).
fact1(3,5).
fact1(2,2).
fact1(2,10).
fact1(3,1).
fact1(1,1).
fact1(1,6).
fact2(3,a,b)
fact2(2,c,d)
fact2(1,e,f)
That list needs to contain tuples with each containing the second and third Value of fact2, and the added numbers of fact2, whenever the first value of fact1 and fact2 match up.
Maybe it gets clearer when I show what I have so far.
Here is my predicate with the findall statement, which to me seems to get me the closest to where I need to get:
collect_items(List):-
findall((Out1,Out2,Nr),
(fact2(Val1,Out1,Out2),
fact1(Val1,Nr)),
List).
The List I receive from this, looks like this:
List = [(a,b,3),(a,b,5),(a,b,1),(c,d,3),(c,d,2),(c,d,10),(e,f,1),(e,f,6)]
But really I need the list to look like this:
List = [(a,b,9),(c,d,15),(e,f,7)]
Meaning that, whenever the first two elements of a tuple match up, the numbers, which are the third element of the tuple, should be added together.
I do not know however how to even approach something like this, as I have always read, that as soon as the list is set, it cannot be changed, since prolog is functional and declarative.
So I think I somehow need to match every element against the one before or after it (since the list will always be sortet by the Out1 and Out2 variables), and if they match, add the third value in the tuple together. The problem is, that I have no idea how.
To me it looks like this can not realy be done within the findall itself but would need to be done after the findall
I am a true beginner and would appreciate any help. In this case it would be best, if the solution was all in one predicate.
Here is another solution that uses more than one predicate:
collect_items(Result):-
findall([Out1,Out2,Nr],(fact2(Val1,Out1,Out2),fact1(Val1,Nr)),[[OutA, OutB, N]|B]),
sumElements([[OutA, OutB, N]|B], Result).
sumElements([],[]).
sumElements([[Out, Outt, N]|B], [[Out, Outt, SumLocal]|RestOfList]):-
findall([Out, Outt, X], member([Out, Outt, X], [[Out, Outt, N]|B]), SubList),
sumLocal(SubList, SumLocal),
subtract([[Out, Outt, N]|B], SubList, New),
sumElements(New, RestOfList).
sumLocal([],0).
sumLocal([[_,_,S]|B], T):-
sumLocal(B, R),
T is S + R.
output:
?- collect_items(Result).
Result = [[a, b, 9], [c, d, 15], [e, f, 7]].
with library aggregate:
collect_items(L) :-
setof((U,V,S),
K^aggregate((set(X/Y),sum(N)), (
fact2(K,X,Y),
fact1(K,N)
), ([U/V],S)), L).
we get
?- collect_items(L).
L = [(a, b, 9), (c, d, 15), (e, f, 7)].
You are not right here
since prolog is functional and declarative
Prolog is relational and declarative
I'm currently writing a predicate that will run through a list of lists and insert a value I have calculated onto the beginning of the list
Step one is easy, just perform the calculation for each list and unify variable N with it.
checkthrough([]).
checkthrough([H|T]):-
count_validentries(H,N),
checkthrough(T).
What I'm trying to achieve now is to put that variable N onto the beginning of each of my sublists, so each list begins with the count of valid entries.
I have attempted to do this using an accumulator. Attempting to start with an empty list, and to every time add the new value N and the head of the list to it:
checkthrough([],Sofar,Lastone).
checkthrough([H|T],Sofar,Lastone):-
count_validentries(H,N),
Newsofar is [N,H|Sofar],
checkthrough(T,Newsofar,Lastone).
I'm quite sure I'm making a really stupid mistake somewhere along the lines. This is not valid Prolog syntax, failing with Arithmetic:' [2 internal variables]' is not a function.
Does anyone have any tips please?
Using meta-predicate maplist/3 and Prolog lambda simply write:
?- use_module(library(lambda)).
?- maplist(\Es^[N|Es]^count_validentries(Es,N), Ess, Xss).
Also, I'd guess that you're really looking for (-)/2 pairs which is how key-value pairs are commonly represented—by library predicates and the built-in predicate keysort/2. Consider:
?- Ess = [[a,b,c],[d,e],[],[f]],
maplist(\Es^(N-Es)^length(Es,N), Ess, Xss),
keysort(Xss, Yss).
Ess = [ [a,b,c], [d,e], [], [f]],
Xss = [3-[a,b,c], 2-[d,e], 0-[], 1-[f]],
Yss = [0-[], 1-[f], 2-[d,e], 3-[a,b,c]].
Maybe
checkthrough([],Sofar,Sofar).
checkthrough([H|T],Sofar,Lastone):-
count_validentries(H,N),
checkthrough(T,[[N|H]|Sofar],Lastone).
but you'll end up with the list reversed. Keeping it simpler will help
checkthrough([],[]).
checkthrough([H|T],[[N|H]|Rest]):-
count_validentries(H,N),
checkthrough(T,Rest).
or better, if you're running a recent version of SWI-Prolog:
checkthrough(L,L1) :-
maplist([E,E1]>>(count_validentries(E,N),E1=[N|E]), L,L1).
I have two lists in python.
a=[1,4,5]
b=[4,1,5]
What i need is to order b according to a. Is there any methods to do it so simply without any
loops?
The easiest way to do this would be to use zip to combine the elements of the two lists into tuples:
a, b = zip(*sorted(zip(a, b)))
sorted will compare the tuples by their first element (the element from a) first; zip(*...) will "unzip" the sorted list.
or may be just check everything is perfect then..copy list a for b
if all(x in b for x in a) and len(a)==len(b):
b=a[:]
If you want to make list2 identical to list1, you don't need to mess with order or re-arrange anything, just replace list2 with a copy of list1:
list2 = list(list1)
list() takes any iterable and produces a new list from it, so we can use this to copy list1, thus creating two lists that are exactly the same.
It might also be possible to just do list2 = list1, but do note that this will cause any changes to either to affect the other (as they point to the same object), so this is probably not what you want.
If list2 is referenced elsewhere, and thus needs to remain the same object, it's possible to replace every value in the list using list2[:] = list1.
In general, you probably want the first solution.
Sort b based on items' index in a, with all items not in a at the end.
>>> a=[1,4,5,2]
>>> b=[4,3,1,5]
>>> sorted(b, key=lambda x:a.index(x) if x in a else len(a))
[1, 4, 5, 3]