Order by pair comparisons

From Rosetta Code
Revision as of 06:51, 14 April 2021 by rosettacode>Paddy3118 (→‎{{header|Julia}}: Clarified-review)
Order by pair comparisons is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Assume we have a set of items that can be sorted into an order by the user.

The user is presented with pairs of items from the set in no order, the user states which item is less than, equal to, or greater than the other (with respect to their relative positions if fully ordered).

Write a function that given items that the user can order, asks the user to give the result of comparing two items at a time and uses the comparison results to eventually return the items in order.

Try and minimise the comparisons the user is asked for.

Show on this page, the function ordering the colours of the rainbow:

   violet red green indigo blue yellow orange

The correct ordering being:

   red orange yellow green blue indigo violet

Note:

  • Asking for/receiving user comparisons is a part of the task.
  • The seven colours can form twenty-one different pairs.
  • A routine that does not ask the user "too many" comparison questions should be used.



Julia

This task has been clarified. Its programming examples are in need of review to ensure that they still fit the requirements of the task.

Using external function

Uses shell sort, just because it sort of fits the task, metaphorically, as if it were with variously colored peas. <lang julia>const nrequests = [0] const ordering = Dict("violet" => 7, "red" => 1, "green" => 4, "indigo" => 6, "blue" => 5,

                     "yellow" => 3, "orange" => 2)

tellmeifgt(x, y) = (nrequests[1] += 1; ordering[x] > ordering[y])

function orderbypair!(a::Vector)

   incr = div(length(a), 2)
   while incr > 0
       for i in incr+1:length(a)
           j = i
           tmp = a[i]
           while j > incr && tellmeifgt(a[j - incr], tmp)
               a[j] = a[j-incr]
               j -= incr
           end
           a[j] = tmp
       end
       if incr == 2
           incr = 1
       else
           incr = floor(Int, incr * 5.0 / 11)
       end
   end
   return a

end

const words = String.(split("violet red green indigo blue yellow orange", r"\s+")) println("Unsorted: $words") println("Sorted: $(orderbypair!(words)). Total requests: $(nrequests[1]).")

</lang>

Output:
Unsorted: ["violet", "red", "green", "indigo", "blue", "yellow", "orange"]
Sorted: ["red", "orange", "yellow", "green", "blue", "indigo", "violet"]. Total requests: 14.

Using the builtin sort function

Probably this uses MergeSort internally, per the Julia documentation. <lang julia>const nrequests = [0] const ordering = Dict("violet" => 7, "red" => 1, "green" => 4, "indigo" => 6, "blue" => 5,

                     "yellow" => 3, "orange" => 2)

tellmeiflt(x, y) = (nrequests[1] += 1; ordering[x] < ordering[y]) const words = String.(split("violet red green indigo blue yellow orange", r"\s+")) println("Unsorted: $words") println("Sorted: $(sort!(words, lt=tellmeiflt)). Total requests: $(nrequests[1]).")

</lang>

Output:
Unsorted: ["violet", "red", "green", "indigo", "blue", "yellow", "orange"]
Sorted: ["red", "orange", "yellow", "green", "blue", "indigo", "violet"]. Total requests: 19.

Python

Uses binary search to insert successive items into a growing ordered list. Comparisons are asked for.

<lang python>def _insort_right(a, x, q):

   """
   Insert item x in list a, and keep it sorted assuming a is sorted.
   If x is already in a, insert it to the right of the rightmost x.
   """
   lo, hi = 0, len(a)
   while lo < hi:
       mid = (lo+hi)//2
       q += 1
       less = input(f"{q:2}: IS {x:>6} LESS-THAN {a[mid]:>6} ? y/n: ").strip().lower() == 'y'
       if less: hi = mid
       else: lo = mid+1
   a.insert(lo, x)
   return q

def order(items):

   ordered, q = [], 0
   for item in items:
       q = _insort_right(ordered, item, q)
   return ordered, q

if __name__ == '__main__':

   items = 'violet red green indigo blue yellow orange'.split()
   ans, questions = order(items)
   print('\n' + ' '.join(ans))</lang>
Output:
 1: IS    red LESS-THAN violet ? y/n: y

 2: IS  green LESS-THAN violet ? y/n: y

 3: IS  green LESS-THAN    red ? y/n: n

 4: IS indigo LESS-THAN  green ? y/n: n

 5: IS indigo LESS-THAN violet ? y/n: y

 6: IS   blue LESS-THAN indigo ? y/n: y

 7: IS   blue LESS-THAN  green ? y/n: n

 8: IS yellow LESS-THAN   blue ? y/n: y

 9: IS yellow LESS-THAN  green ? y/n: y

10: IS yellow LESS-THAN    red ? y/n: n

11: IS orange LESS-THAN   blue ? y/n: y

12: IS orange LESS-THAN yellow ? y/n: y

13: IS orange LESS-THAN    red ? y/n: n

red orange yellow green blue indigo violet