Related
I have an array of similar objects, with an attribute a which can have values b or c. The array can be considered as a collection of rows, where each pair of items in the array represent one row. I've just listed the values of attribute a for simplicity's sake,
Example:
array = [c, b, b, c, c, c, b]
# array[0], array[1] is one row (c, b)
# array[2], array[3] is another (b, c)
# ...
There can be no row of just (b, b), and if that is the case then one of the b values must be swapped for the closest c value in the array. If there are no more c values, then the array is valid as long as the b values are left at the end of the array.
The final row of the array can consist of just one value, i. e. (b, ).
Example:
array = [b, c, b, b, c, b, b, b, c, b, b, c, c]
# becomes
array = [b, c, b, c, b, b, b, b, c, b, b, c, c]
array = [b, c, b, c, b, c, b, b, b, b, b, c, c]
array = [b, c, b, c, b, c, b, c, b, b, b, b, c]
array = [b, c, b, c, b, c, b, c, b, c, b, b, b]
# rows: (b, c), (b, c), (b, c), (b, c), (b, c), (b, b,), (b, )
This is the solution I came up with, which I don't really like (because it's very imperative and verbose)
while true do
cand = nil
array.each_slice(2) do |item, nxt|
return if nxt.nil?
# pseudo-code: assume b? returns true for a == b
next unless item.b? && nxt.b?
cand = nxt
break
end
swap_cand = array.slice(array.index(cand), array.length).reject{ |item| item.popular? }.first
return if swap_cand.nil?
old_index, new_index = array.index(cand), array.index(swap_cand)
array[old_index], array[new_index] = array[new_index], array[old_index]
end
A problem I kept running into was that I couldn't mutate an array while iterating over it, necessitating two loops.
edit Cleaned up some of the break statements per the suggestions from #7stud.
Enumerable#chunk is well-suited for this problem.
Code
def valid?(arr, b)
arr.chunk { |e| e }
.map(&:last)[0..-2]
.select { |e| e.first == b }
.max_by(&:size)
.size <= 2
end
Example
b = 0
c = 1
valid?([c, b, b, c, b, b, b], b) #=> true
valid?([c, b, b, b, c, c, b], b) #=> false
Explanation
b = 0
c = 1
arr = [c, b, b, c, b, b, b]
#=> [1, 0, 0, 1, 0, 0, 0]
enum = arr.chunk { |e| e }
#=> #<Enumerator: #<Enumerator::Generator:0x0000010205aa70>:each>
enum.to_a # Let's examine the elements of `enum`
#=> [[1, [1]], [0, [0, 0]], [1, [1]], [0, [0, 0, 0]]]
a = enum.map(&:last)
#=> [[1], [0, 0], [1], [0, 0, 0]]
d = a[0..-2] # disregard last value, which may or may not be an array of `b`'s
#=> [[1], [0, 0], [1]]
e = d.select { |e| e.first == b }
#=> [[0, 0]]
f = e.max_by(&:size)
#=> [0, 0]
g = f.size
#=> 2
g <= 2
#=> true
I don't know how can I achieve the following:
I want to count the number of times a certain condition (whose values are unknown) is met.
For instance, if I have the lists [A1,A2,A3] and [B1,B2,B3], how can I
create a list [R1,R2,R3] where Ri is 1 if Ai=Bi and 0 if not.
This is the basis of the "program".
:- use_module(library(clpfd)).
main(A,B) :-
length(A,3),
domain(A,1,3),
all_different(A),
length(B,3),
domain(B,1,3),
all_different(B),
append(A,B,L),
labeling([],L).
you should 'reify' your conditions, posting constraints of the form
reify(A,B,C) :-
C #<==> A #= B.
between pairs of variables. maplist/3 it's an handy shortcut
:- use_module(library(clpfd)).
% simulate domain/3 in SWI-prolog
domain(Vs,L,H) :- Vs ins L..H.
reify(A,B,C) :-
C #<==> A #= B.
main(A,B,C) :-
length(A,3),
domain(A,1,3),
all_different(A),
length(B,3),
domain(B,1,3),
all_different(B),
maplist(reify, A,B,C),
labeling([],A),
labeling([],B).
yields
1 ?- main(A,B,C).
A = B, B = [1, 2, 3],
C = [1, 1, 1] ;
A = [1, 2, 3],
B = [1, 3, 2],
C = [1, 0, 0] ;
A = [1, 2, 3],
B = [2, 1, 3],
C = [0, 0, 1]
etc ....
I'm new in Prolog world. I want to find out if a permutation is 'one-cycle'.
I'm trying to write a predicate to generate cycle from permutation. Here is my code (not working):
find_next([E|_], [N|_], E, N).
find_next([_|L1], [_|L2], E, N) :-
find_next(L1, L2, E, N).
find_cycle(L1, L2, E, C) :-
append(C, [E], C1),
find_next(L1, L2, E, N),
find_cycle(L1, L2, N, C1).
Permutations are represented by two lists (for example: [1, 2, 3, 4], [3, 4, 2, 1]).
find_next generates next cycle element (N) for element (E) (for example: E=1, N=3).
find_cycle looks for cycle (C) starting from element E.
Unfortunately I don't know how to stop my recurrence when find_next returns N same as first element of cycle C.
EDIT: some examples.
find_cycle([1, 2, 3, 4], [3, 4, 2, 1], 1, X).
should return:
X = [1, 3, 2, 4];
false.
and:
find_cycle([1, 2, 3, 4], [4, 2, 1, 3], 1, X).
should return:
X = [1, 4, 3];
false.
Why?
It is simple decomposition of permutation into disjointed cycles.
Let's analyze second permutation: [1, 2, 3, 4], [4, 2, 1, 3].
Take first element: 1.
1 goes into 4
4 goes into 3
3 goes into 1
end of cycle.
This permutation is not decomposable into one cycle (length of generated cycle is smaller than length of permutation).
To find all the cycles of the permutation:
perm_to_cycles(Perm, NPerm, Cycles):-
perm_struct(Perm, NPerm, PermS),
perm_to_cycles(PermS, [], [], Cycles),
!.
perm_to_cycles([], _, Cycles, Cycles).
%perm_to_cycles([p(Id, Id)|PermS], _, InCycles, Cycles):-
% perm_to_cycles(PermS, [], InCycles, Cycles). % This clause would remove fixed elements
perm_to_cycles([p(Id, Item)|PermS], Cycle, InCycles, Cycles):-
(select(p(Item, NId), PermS, NPermS) ->
perm_to_cycles([p(Item, NId)|NPermS], [Id|Cycle], InCycles, Cycles) ;
(
reverse([Id|Cycle], RCycle),
perm_to_cycles(PermS, [], [RCycle|InCycles], Cycles)
)
).
perm_struct([], [], []).
perm_struct([Item|Perm], [NItem|NPerm], [p(Item, NItem)|PermS]):-
perm_struct(Perm, NPerm, PermS).
The commented clause would remove fixed elements of list of cycles.
To get only one-cycle permutations you can constrain the third argument to be a one-element list. For example:
?- perm_to_cycles([1, 2, 3, 4], [3, 4, 2, 1], [X]).
X = [1, 3, 2, 4]
?- perm_to_cycles([1, 2, 3, 4], [4, 2, 1, 3], [X]).
false.
?- perm_to_cycles([1, 2, 3, 4], [4, 2, 1, 3], X).
X = X = [[2], [1, 4, 3]].
-Hi Dave, here is my solution to the problem. I followed your instructions like 1 goes to 4 , 4 goes to 3 etc and here is what I came up with. First I create arcs between the elements of the two lists(permutations) and then I simply move through the created graph using find_cycle (until our nodes start repeating ). I tried to use variable names that are self explanatory but if have hard time understanding the code let me know.
create_arcs([],[],[]).
create_arcs([H|T],[H1|T1],[arc(H,H1)|RezArc]) :- create_arcs(T,T1,RezArc).
find_cycle(Perm,Perm2,E,X) :- create_arcs(Perm,Perm2,Arcs),
find_cycle(E,Arcs,[],X).
find_cycle(StartNode,Arcs,LocRez,LocRez) :- member(arc(StartNode,NextNode),Arcs),
member(StartNode,LocRez).
find_cycle(StartNode,Arcs,LocRez,FinalRez) :- member(arc(StartNode,NextNode),Arcs),
not(member(StartNode,LocRez)),
append(LocRez,[StartNode],LocRezNew),
find_cycle(NextNode,Arcs,LocRezNew,FinalRez).
List:
Bag = [
(a, 1, 2),
(b, 2, 3),
(c, 3, 4)],
I want to compare the result of 1*2 in list a, 2*3 in list b, and 3*4 in list c.
And sort the result and output, how to do that in PROLOG?
Thank you.
You can do it using sort/2:
?- findall([Result, Name],
(member((Name, A, B), [(a, 3, 2), (b, 1, 3), (c, 3, 4)]),
Result is A*B),Output),
sort(Output, SOutput).
SOutput = [[2, a], [6, b], [12, c]].
Not that this needs another answer, but a DCG which relates a list of terms such as (c,3,4) as 'input' with a list of pairs c-12 as 'output' is:
task([]) --> [].
task([A-B|Ls]) --> [(A, X,Y)], {B is X*Y}, task(Ls).
Then sort/4-ing the pairs by the value:
?- Bag = [(a, 1, 2), (b, 2, 3), (c, 3, 4)],
phrase(task(_Pairs), Bag),
sort(1, #>=, _Pairs, Result).
Result = [c-12, b-6, a-2]
Relatively new to Mathematica, so this might be an easy question. With two lists I need to sort both by one of them, while ignoring any non-numeric values
Example:
x={a, b, c, d, e, f, g};
y={-2, Indeterminate, -3, -Infinity, -1, Apples, 5};
(Also have z=Partition[Riffle[x,y], 2] if that's a little bit better to work with)
Result looking for:
xn={g, e, a, c}
yn={5, -1, -2, -3}
(Or zn equivalent from using z)
Here is one way:
Transpose#Reverse#SortBy[Cases[Transpose[{y, x}], {_?NumericQ, _}], First]
which returns
{{5, -1, -2, -3}, {g, e, a, c}}