I have some code that takes a given list of pairs of numbers and solves for chains of 7. However, it takes an obnoxious amount of time to solve for even one (well, i haven't solved for 1 yet and it has been a large amount of time). I was wondering if there was a better/more efficient way of coding this.
Here's what I did, with out the numbers in the list "L". (the list looks like such: L= [[1,2],[2,3],...])
length(L,LEN),
interval(N1,1,LEN),
interval(N2,1,LEN),
interval(N3,1,LEN),
interval(N4,1,LEN),
interval(N5,1,LEN),
interval(N6,1,LEN),
interval(N7,1,LEN),
nth1(N1,L,A),
nth1(N2,L,B),
nth1(N3,L,C),
nth1(N4,L,D),
nth1(N5,L,E),
nth1(N6,L,F),
nth1(N7,L,G),
nth1(2,A,A2),
nth1(1,B,B1),
A2 = B1,
nth1(2,B,B2),
nth1(1,C,C1),
B2 = C1,
nth1(2,C,C2),
nth1(1,D,D1),
C2 = D1,
nth1(2,D,D2),
nth1(1,E,E1),
D2 = E1,
nth1(2,E,E2),
nth1(1,F,F1),
E2 = F1,
nth1(2,F,F2),
nth1(1,G,G1),
F2 = G1,
nth1(2,G,G2),
nth1(1,A,A1),
G2 = A1,
R = (A,B,C,D,E,F,G).
If I understand your intention correctly, you can write this shorter as
use_module(library(clpfd)).
q(L,R) :-
[A,B,C,D,E,F,G] ins 1 .. 7,
R = [[A,B],[B,C],[C,D],[D,E],[E,F],[F,G],[G,A]],
permutation(L, R),
label([A,B,C,D,E,F,G]).
Example:
3 ?- q([[1,7],[2,3],[5,4],[3,1],[7,6],[6,5],[4,2]],X).
X = [[1, 7], [7, 6], [6, 5], [5, 4], [4, 2], [2, 3], [3, 1]] ;
X = [[2, 3], [3, 1], [1, 7], [7, 6], [6, 5], [5, 4], [4, 2]] ;
X = [[5, 4], [4, 2], [2, 3], [3, 1], [1, 7], [7, 6], [6, 5]] ;
X = [[3, 1], [1, 7], [7, 6], [6, 5], [5, 4], [4, 2], [2, 3]] ;
X = [[7, 6], [6, 5], [5, 4], [4, 2], [2, 3], [3, 1], [1, 7]] ;
X = [[6, 5], [5, 4], [4, 2], [2, 3], [3, 1], [1, 7], [7, 6]] ;
X = [[4, 2], [2, 3], [3, 1], [1, 7], [7, 6], [6, 5], [5, 4]] ;
false.
But your question is really unclear.
update: We can create the kind of lists we use above, of any length, with
vars(N, Vars):-
length(Vars, N).
pairs(Vars, N, Pairs):- % assuming vars(N, Vars)
N #> 0,
append(Vars,[A],[A|B]), % |B| = N
maplist( pair, Vars, B, Pairs).
pair( A, B, [A,B]).
Such that q/2 can be generalized as
gen_q(L,R) :-
length( L, N),
vars( N, Vars),
Vars ins 1 .. N,
pairs( Vars, N, R),
permutation(L, R),
label(Vars).
But computational feasibility of this for larger inputs is another matter entirely. The brute force of permutation/2 may have to be replaced with something more specific.
Also, the N results produced comprise a clear pattern; there's no need to re-enter the search to produce them all after the first one is found.
Related
I have two lists of lists as follows. To merge them, I usually do the following:
>>>from itertools import imap, ilist
>>>a = [1,2,3]
>>>b = [4,5,6]
>>> c = list(imap(list,izip(a,b)))
>>> c
[[1, 4]], [2, 5], [3, 6]]
However, now I have a list of list as follows:
[[1,2,3],
[4,5,6],
[7,8,9],
]
How do I iterate through each list and pass it to the izip function to obtain the following output:
[[1,4,7],[2,5,8],[3,6,9]]
Answer for edited Question:
>>> input_list=[[1,2,3],
[4,5,6],
[7,8,9],
]
Using map and zip:
>>> map(list,zip(*input_list))
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
Using imap and izip:
>>> list(imap(list,list(izip(*input_list))))
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
Answer for previous question:
By using list comprehension and two for loops:
input_list =[[[1],[2],[3]],
[[4],[5],[6]],
[[7],[8],[9]],
]
out_list = [[] for i in range(len(input_list))]
for each_row in input_list:
for i in range(len(each_row)):
out_list[i].extend(each_row[i])
print out_list
Output:
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
I think u need something like this:
input_list =[[1,2,3],
[4,5,6],
[7,8,9],
]
result = []
for i in range(len(input_list)):
temp = []
for list in input_list:
temp.append(list[i])
result.append(temp)
print result
result will be:
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
I have this nested list:
list = [[1, 2, 3, 4],
[2, 7, 2, 1],
[3, 3, 7, 5],
[4, 4, 1, 7]]
And I'm trying to skip the first list of this nested list, and the first element of each list. I want it to become like this:
list = [[7, 2, 1],
[3, 7, 5],
[4, 1, 7]]
So far I have this:
% skip first list in list of lists
skip_first_list([_|Tail], Tail).
% attemping to skip first element in each of the lists
skip_first_list([[_ | HeadTail] | Tail], X) :-
skip_first_list(Tail, R),
append(R, [HeadTail], X).
Which does not produce the correct result:
?- skip_first_list([[1, 2, 3, 4], [2, 7, 2, 1], [3, 3, 7, 5], [4, 4, 1, 7]], X).
X = [[2, 7, 2, 1], [3, 3, 7, 5], [4, 4, 1, 7]] ;
X = [[3, 3, 7, 5], [4, 4, 1, 7], [2, 3, 4]] ;
X = [[4, 4, 1, 7], [7, 2, 1], [2, 3, 4]] ;
X = [[3, 7, 5], [7, 2, 1], [2, 3, 4]] ;
false.
Whereas I'm after this answer:
X = [[7, 2, 1], [3, 7, 5], [4, 1, 7]]
My result so far seems to be showing I'm appending in a reverse/incorrect order, How can I fix this? I don't really understand what order Prolog evaluates expressions. Any any would be appreciated.
Well the specification is that you provide a list of lists and that:
the first sublist is ignored (not part of the output); and
that for the remaining sublists, all heads are ignored as well.
So we better split this into two predicates:
remove_heads/2, which removes the heads of all sublists; and
remove_upper_left/2 which remove the first sublist, and then uses the above predicate to pop the heads of the sublists.
We can perform remove_heads/2 for instance with recursion:
remove_heads([],[]).
remove_heads([[_|H]|T],[H|T2]) :-
remove_heads(T,T2).
finally our remove_upper_left/2 simply ignores the head of the list, and makes a call to remove_heads with the tail:
remove_upper_left([_|T],T2) :-
remove_heads(T,T2).
Or in full:
remove_heads([],[]).
remove_heads([[_|H]|T],[H|T2]) :-
remove_heads(T,T2).
remove_upper_left([_|T],T2) :-
remove_heads(T,T2).
This then produces:
?- remove_upper_left([[1, 2, 3, 4], [2, 7, 2, 1], [3, 3, 7, 5], [4, 4, 1, 7]],X).
X = [[7, 2, 1], [3, 7, 5], [4, 1, 7]].
and works in the opposite direction as well:
?- remove_upper_left(X, [[1, 2, 3, 4], [2, 7, 2, 1], [3, 3, 7, 5], [4, 4, 1, 7]]).
X = [_G1364, [_G1370, 1, 2, 3, 4], [_G1376, 2, 7, 2, 1], [_G1382, 3, 3, 7, 5], [_G1388, 4, 4, 1|...]].
So here it prepends a variable to every list, and prepends a variable (possibly a sublist) to the output.
Furthermore we have here two predicates at the price of one: we can also use remove_heads/2 in the future if we want to pop the heads of all the sublists in a list of lists.
I want my program to take numbers from 1 to X and randomly distribute those numbers between X/2 numbers of lists Y times. I don't want a number to be repeated during one shuffle, also I don't want the lists to repeat at all. So if there is list [1,2] there shouldn't be another list containing 1 or 2 in same shuffle and there shouldn't be another [1,2] or [2,1] in the whole result.
This is what I came up with, however, it keeps on repeating numbers. Any adice?
import random
def Shuffler():
amount = int(raw_input("Numbers up to: "))
times = int(raw_input("Number of shuffles: "))
numberslist = range(1,amount+1)
twos = []
thisshuffle = []
final = []
while len(final) < (amount/2)*times:
twos = []
thisshuffle = []
while len(twos) < 2:
if len(numberslist)!=0:
randomnumber = random.choice(numberslist)
if (randomnumber in twos) or (randomnumber in thisshuffle):
numberslist.remove(randomnumber)
else:
twos.append(randomnumber)
thisshuffle.append(randomnumber)
numberslist.remove(randomnumber)
else:
numberslist = range(1,amount+1)
if (twos or list(reversed(twos))) not in final:
final.append(twos)
k=0
for i in range(times): #this shit prints shit
print "%s:" % (i+1), final[k:k+amount/2]
print
k = k + amount/2
Shuffler()
Shuffler()
As ccf pointed out, your requirements aren't trivial. A few more steps and you'd have a sudoku generator :)
I tried a few solutions but they either didn't produce random output or were rather inefficient. Ccf's solution is clearly well written but it seems to have the same problem; it produces ordered output (e.g. [1, 2], [1, 3], [1, 4], [1, 5], [1, 6]).
#cff - wouldn't it be better to use itertools.combinations rather than itertools.permutations to avoid generating repetitions?
Here's a "solution" that's quite similar to ccf's (doesn't produce random output either):
import itertools
def Shuffler():
amount = int(raw_input("Numbers up to: "))
times = int(raw_input("Number of shuffles: "))
rng = range(1, amount+1)
perms = list(itertools.combinations(rng, 2))
lst_single = []
lst_all = []
for p in perms:
if len(lst_all) >= times:
for i, lst in enumerate(lst_all):
print str(i+1) + ": ", lst
break
if len(lst_single) == amount/2:
lst_all.append(lst_single)
lst_single = []
elif p[0] < p[1]:
p = list(p)
lst_single.append(p)
Shuffler()
Output
Numbers up to: 6
Number of shuffles: 3
1: [[1, 2], [1, 3], [1, 4]]
2: [[1, 6], [2, 3], [2, 4]]
3: [[2, 6], [3, 4], [3, 5]]
And here's a slightly hackish solution that seems to produce the output you want but in an inefficient way. It relies on a set for filtering out unwanted combinations but still wastes resources producing them in the first place.
import random
def Shuffler():
amount = int(raw_input("Numbers up to: "))
times = int(raw_input("Number of shuffles: "))
rng = range(1, amount+1)
final = []
lst_len = amount/2
combos_unique = set()
while len(combos_unique) < lst_len*times:
combo_rand = random.sample(rng, 2)
if combo_rand[0] < combo_rand[1]:
combos_unique.add(tuple(combo_rand))
tmp = []
for combo in combos_unique:
tmp.append(list(combo))
if len(tmp) >= lst_len:
final.append(tmp)
tmp = []
for i, lst in enumerate(final):
print str(i+1) + ": ", lst
Shuffler()
Output
Numbers up to: 6
Number of shuffles: 3
1: [[2, 6], [4, 6], [5, 6]]
2: [[4, 5], [1, 3], [1, 6]]
3: [[3, 4], [2, 4], [3, 5]]
You don't want any repeated numbers in one shuffle, and any repeated list ... and so on. This is not an easy task. Plus another fact is that, the unique sets of numbers are fixed, which cannot be set too high. For example, if you set "Numbers up to:" 5, and "Number of shuffles: " 20, for sure you will get repeated numbers.
The issue with your code, I see, is in this if statement:
if (twos or list(reversed(twos))) not in final:
final.append(twos)
(twos or list(reversed(twos))) is logical OR, the result is twos, because twos is not empty. I suggest you change the if statement to:
if (twos not in final) and (list(reversed(twos)) not in final):
final.append(twos)
The following code (python 2.7x) uses permutations and shuffle to generate numbers list. Next, make the list unique (e.g., no [1,2] and [2,1] in same list). then, divide them into groups based on number of shuffles specified by the user. Press any letter, script will exit. Hope it helps:
from itertools import permutations
from random import shuffle
def Shuffler():
try:
amount = input("Numbers up to: ")
p = list(permutations(range(1, amount + 1), 2))
p_uniq = [list(x) for x in p if x[::-1] in p and x[0]<=x[1]]
shuf_max = len(p_uniq) /(amount / 2)
times = shuf_max + 1 # set a higher value to trigger prompt
while times > shuf_max:
shuffle(p_uniq) # shuffle the unique list in place
times = input("Number of shuffles (MAX %s): " % (shuf_max))
else:
for i, group in enumerate(list(zip(*[iter(p_uniq[: (amount /2) * times + 1])]* (amount/2)))):
print "%i: " % (i + 1), list(group)
Shuffler()
except:
print 'quitting...'
Shuffler()
Output:
Numbers up to: 10
Number of shuffles (MAX 9): 8
1: [[6, 7], [1, 9], [2, 5], [5, 9], [9, 10]]
2: [[1, 10], [3, 8], [4, 10], [8, 10], [1, 5]]
3: [[1, 4], [6, 8], [3, 6], [2, 4], [4, 7]]
4: [[2, 10], [5, 8], [3, 9], [1, 7], [4, 9]]
5: [[1, 2], [7, 9], [1, 3], [6, 9], [1, 6]]
6: [[2, 9], [4, 8], [3, 5], [8, 9], [7, 10]]
7: [[2, 7], [2, 3], [7, 8], [3, 7], [3, 10]]
8: [[3, 4], [2, 6], [5, 6], [5, 7], [4, 6]]
Numbers up to:
I am trying to make a list*list of all permutations from 1 to N
Example: perm(3, X). -> X = [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
I am instead getting
X = [1, 2, 3]
X = [1, 3, 2]
X = [2, 1, 3]
X = [2, 3, 1]
X = [3, 1, 2]
X = [3, 2, 1]
and having to keep hitting next. My question is how would I put all values of X into a list like the example run that I want. Here is my existing code:
permHelp([],[]).
permHelp(List,[H|Finish]):-delete(H,List,Rest),permHelp(Rest,Finish).
delete(X,[X|T],T).
delete(X,[H|T],[H|NT]):-delete(X,T,NT).
createList(0, L, L) :- !.
createList(N, R, L) :- N > 0, N1 is N-1, createList(N1, [N|R], L).
perm(N, X):- createList(N, [], L), permHelp(L, X).
perm(N, X):-
createList(N, [], L),
list_allperms(L, X).
With list_allperms/2 defined in another answer.
What you call permHelp should rather be called permutation.
I'm trying to write a predicate that divides a list into N parts.
This is what I have so far.
partition(1, List, List).
partition(N, List, [X,Y|Rest]):-
chop(List, X, Y),
member(NextToChop, [X,Y]), %Choose one of the new parts to chop further.
NewN is N-1,
partition(NewN, NextToChop, Rest).
chop(List, _, _):-
length(List, Length),
Length < 2, %You can't chop something that doesn't have at least 2 elements
fail,!.
chop(List, Deel1, Deel2):-
append(Deel1, Deel2, List),
Deel1 \= [],
Deel2 \= [].
The idea is to keep chopping parts of the list into two other parts until I have N pieces.
I have mediocre results with this approach:
?- partition(2, [1,2,3,4], List).
List = [[1], [2, 3, 4], 1] ;
List = [[1], [2, 3, 4], 2, 3, 4] ;
List = [[1, 2], [3, 4], 1, 2] ;
List = [[1, 2], [3, 4], 3, 4] ;
List = [[1, 2, 3], [4], 1, 2, 3] ;
List = [[1, 2, 3], [4], 4] ;
false.
So I get what I want, but I get it two times and there are some other things attached.
When dividing into 3 parts things get worse:
?- partition(3, [1,2,3,4], List).
List = [[1], [2, 3, 4], [2], [3, 4], 2] ;
List = [[1], [2, 3, 4], [2], [3, 4], 3, 4] ;
List = [[1], [2, 3, 4], [2, 3], [4], 2, 3] ;
List = [[1], [2, 3, 4], [2, 3], [4], 4] ;
List = [[1, 2], [3, 4], [1], [2], 1] ;
List = [[1, 2], [3, 4], [1], [2], 2] ;
List = [[1, 2], [3, 4], [3], [4], 3] ;
List = [[1, 2], [3, 4], [3], [4], 4] ;
List = [[1, 2, 3], [4], [1], [2, 3], 1] ;
List = [[1, 2, 3], [4], [1], [2, 3], 2, 3] ;
List = [[1, 2, 3], [4], [1, 2], [3], 1, 2] ;
List = [[1, 2, 3], [4], [1, 2], [3], 3] ;
false.
Another idea is using prefix but I don't know how that would really work. To use that I should be able to let Prolog know that it needs to take a prefix that's not too short and not too long either, so I don't take a prefix that's too long so there's nothing left for a next recursion step.
Can anyone point me in the right direction?
Little clarification: the predicate should return all posibilities of dividing the list in N parts (not including empty lists).
When describing relations that involve lists, DCGs are often very useful. Consider:
list_n_parts(List, N, Parts) :-
length(Parts, N),
phrase(parts(Parts), List).
parts([]) --> [].
parts([Part|Parts]) --> part(Part), parts(Parts).
part([P|Ps]) --> [P], list(Ps).
list([]) --> [].
list([L|Ls]) --> [L], list(Ls).
Sample query:
?- list_n_parts([1,2,3,4], 2, Ps).
Ps = [[1], [2, 3, 4]] ;
Ps = [[1, 2], [3, 4]] ;
Ps = [[1, 2, 3], [4]] ;
false.
Here is the basic way I'd use to implement that (using append/2 and length/2) :
list_n_parts(List, Parts, Result) :-
length(Result, Parts),
append(Result, List).
Now, that doesn't totally complies to your expectations : it allows for [].
One idea to fix that is to use a maplist call to format the Resulting list beforehand :
list_n_parts(List, Parts, Result) :-
length(Result, Parts),
using copy_term/2, the maplist/2 call looks like :
maplist(copy_term([_|_]), Result),
using functor/3 (credits to #false), it would look like :
maplist(functor('.', 2), Result),
using lambda.pl you could write :
maplist(\[_|_]^true, Result),
since the '\' already performs a term copy (thanks #false).
The only thing left is the append/2 call:
append(Result, List).
Another idea would be to use forall/2 filtering (maybe simpler to get, but worse in complexity) :
list_n_parts(List, Parts, Result) :-
length(Result, Parts),
append(Result, List),
forall(member(X, Result), X \= []).
etc...