Setting order method in Sicstus prolog Samsort - prolog

I am trying to sort a list of lists such as Books=[[5,1,science,24,3,2018],[6,1,math,24,3,2019],[4,2,science,24,5,2019],[6,2,science,23,3,2019],[3,1,math,24,3,2020]]. I want to order this list based on the 5th value of each element. I tried to use
samsort(sortDateBooks, Books, Output).
sortDateBooks(Book1,Book2):-nth0(5,Book1, Date1),nth0(5,Book2, Date2), Date1<Date2.
The output variable is never filled with data and the original list is also not changed.
I feel that I am not declaring de order predicate properly but can't find any examples.
Thank you for your help.

Well, I noticed I had forgotten to import the samsort library and because of the way it is used no error would be shown. Many thanks to #Reema Q Khan that provided a very usefull workaround and a easy explanation.

I am not sure if this is what you want to do, if yes, then this may give you some hints:
1. Here collect dates will act as findall. It will search for all the years and put them in a list e.g. [2019,2018,2019,2019,2020].
2. sortBook(Sorted) predicate first finds all the Years using collectdates predicate, then sorts them. Notice that in sort I've used #=<, this will not remove any repeated values. You will get [2018,2019,2019,2019,2020].
3. s predicate simply takes each year, searches for the information and puts it in a List.
s predicate will take each year and check through each book, so this may lead to extras. append is used to decrease extra brackets, set predicate simply removes duplicates if any.
sortBook(Sorted):-
Book=[[6,2,science,23,3,2019],[5,1,science,24,3,2018],[6,1,math,24,3,2019],[4,2,science,24,5,2019]
,[3,1,math,24,3,2020]],
collectdates(Book,Clist),
sort(0, #=<, Clist, SList),
s(SList,Book,Sorted1),append(Sorted1,Sorted2),set(Sorted2,Sorted).
collectdates([],[]).
collectdates([H|T],[Last|List]):-
last(H,Last),
collectdates(T,List).
s([],_,[]).
s([H|T],[B|L],[W|List]):-
sortBook1(H,[B|L],W),
s(T,[B|L],List).
sortBook1(_,[],[]).
sortBook1(H,[B|L],[B|List]):-
member(H,B),
sortBook1(H,L,List).
sortBook1(H,[B|L],List):-
\+member(H,B),
sortBook1(H,L,List).
set([],[]).
set([H|T],[H|T2]):-
subtract(T,[H],T3),
set(T3,T2).
Example:
?-sortBook(Sorted).
Sorted = [[5, 1, science, 24, 3, 2018], [6, 2, science, 23, 3, 2019], [6, 1, math, 24, 3, 2019], [4, 2, science, 24, 5, 2019], [3, 1, math, 24, 3, 2020]]
false

Related

Can I count on partition preserving order?

Say I have a sorted Array, such as this:
myArray = [1, 2, 3, 4, 5, 6]
Suppose I call Enumerable#partition on it:
p myArray.partition(&:odd?)
Must the output always be the following?
[[1, 3, 5], [2, 4, 6]]
The documentation doesn't state this; this is what it says:
partition { |obj| block } → [ true_array, false_array ]
partition → an_enumerator
Returns two arrays, the first containing the elements of enum for which the block evaluates to true, the second containing the rest.
If no block is given, an enumerator is returned instead.
But it seems logical to assume partition works this way.
Through testing Matz's interpreter, it appears to be the case that the output works like this, and it makes full sense for it to be like this. However, can I count on partition working this way regardless of the Ruby version or interpreter?
Note: I made implementation-agnostic because I couldn't find any other tag that describes my concern. Feel free to change the tag to something better if you know about it.
No, you can't rely on the order. The reason is parallelism.
A traditional serial implementation of partition would loop through each element of the array evaluating the block one at a time in order. As each call to odd returns, it's immediately pushed into the appropriate true or false array.
Now imagine an implementation which takes advantage of multiple CPU cores. It still iterates through the array in order, but each call to odd can return out of order. odd(myArray[2]) might return before odd(myArray[0]) resulting in [[3, 1, 5], [2, 4, 6]].
List processing idioms such as partition which run a list through a function (most of Enumerable) benefit greatly from parallel processing, and most computers these days have multiple cores. I wouldn't be surprised if a future Ruby implementation took advantage of this. The writers of the API documentation for Enumerable likely carefully omitted any mention of process ordering to leave this optimization possibility open.
The documentation makes no explicit mention of this, but judging from the official code, it does retain ordering:
static VALUE
partition_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, arys))
{
struct MEMO *memo = MEMO_CAST(arys);
VALUE ary;
ENUM_WANT_SVALUE();
if (RTEST(enum_yield(argc, i))) {
ary = memo->v1;
}
else {
ary = memo->v2;
}
rb_ary_push(ary, i);
return Qnil;
}
This code gets called from the public interface.
Essentially, the ordering in which your enumerable emits objects gets retained with the above logic.

Sort ruby middleman array into 3 columns, content in placed in order to display LTR

I am using middleman and have a specific structure that I want my articles to fall into:
.row>
.col-1>article 1, article 4...
.col-2>article 2, article 5...
.col-3>article 3, article 6...
The goal is that the articles read left-to-right, however are stacked in their columns so there is now additional row class that is needed. I have these articles enclosed in a visual card, and want to stack them which is why I have this strange problem to solve.
My question is what is the cleanest ruby way to sort the array into this format? The goal is to use it in a structure like this and be able to account for any number of columns, n.
.row
- page_articles.someProcess(n).each_split(n) do | col |
.column-class
- col.each do | art |
...
Verbatim from group_by doc:
(1..6).group_by{ |i| i%3 }
#=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]}
specifically, use the flatten values
page_articles.group_by.with_index{ |a,i| i%3 }.values.flatten(1)

recursion in prolog - error in base case

I'm trying to write predicate range\3 that takes three parameters the first is the start, the second is the end and return the generated list in the third argument.
E.g rang(1,5,L).
L = [1, 2, 3, 4, 5]
I used this code
range(E,E,[E]).
range(S,E,L):-
S1 is S + 1,
range(S1,E,[S|L]).
But it does not work, when i used trace command to know where is the error i recognized that the base case is useless, I also tried the green cut !in the base case but it does not work range(E,E,[E]),!.
So, if any one knows what is the problem please help me
You're building the list in 'wrong' sense. Consider that when you'll call the base case, it will receive the consed list. How could match a single element list ? Try instead
range(S,E,[S|L]):-
S1 is S + 1,
range(S1,E,L).

Ruby: What is a simple way of searching for certain criteria in an array?

I have an array which I want to make sure all the numbers are between 1 and 6. Here is my array:
guess = [2, 5, 6, 8]
Or something like that. The user inputs the sequence. Anyway, I want a way to check it, and if the numbers aren't all between 1 and 6, it won't break out of the loop. And also could it please be simple!
guess.all?{|i| (1..6).include?(i)}
guess.count{|i| i.between?(1,6)} == guess.size

prolog sort and print best 3

what I have now is,
:-dynamic listofPeople/2.
listofPeople(Mark,Name).
e.g.
19, 'Jos'
92, 'Abdul'
33, 'Izz'
16, 'Xin'
I want it like this -
92, 'Abdul'
33, 'Izz'
19, 'Jos'
which basiclly contains the mark for each student.
I want to print the best 3 marks.
To do that, I blv I have to do sorting. If I do sorting, I will lose the order of the name of the student.
As you can understand by default, what I want is to sort only the marks and change the names position according to the marks as well, so when i print
i get the above output
Code snippets appreciated.
I've answered you in a thread below:
go(N1-G1,N2-G2,N3-G3) :- findall(Grade-Name, listofPeople(Grade,Name), List),
keysort(List, [G1-N1,G2-N2,G3-N3|SortedList]).
On your input go(X,Y,Z) results in X = 'Abdul'-92, Y = 'Izz'-33, Z ='Jos'-19.
Couldn't you sort the list by mark, take the top 3, and then sort THAT by name, before you print?

Resources