Jump to content

Sort disjoint sublist

From Rosetta Code
Revision as of 16:07, 14 February 2011 by rosettacode>Paddy3118 (Undo revision 101602 by 80.180.220.29 (talk) Substituting index for i isn't necessarily a virtue!)
Task
Sort disjoint sublist
You are encouraged to solve this task according to the task description, using any language you may know.

Given a list of values and a set of integer indices into that value list, the task is to sort the values at the given indices, but preserving the values at indices outside the set of those to be sorted.

Make your example work with the following list of values and set of indices:

   values: [7, 6, 5, 4, 3, 2, 1, 0]
   indices: {6, 1, 7}

Where the correct result would be:

   [7, 0, 5, 4, 3, 2, 1, 6].

Note that for one based, rather than the zero-based indexing above, use the indices: {7, 2, 8}. The indices are described as a set rather than a list but any collection-type of those indices may be used as long as the example is insensitive to the order of indices given.

D

Translation of: Python

<lang d>import std.stdio, std.array, std.algorithm;

void disjointSort(T, U)(T[] arr, U[] s) {

   const idxSet = array(uniq(s.sort()));
   auto values = array(map!((i){ return arr[i]; })(idxSet)).sort();
   foreach (i, ix; idxSet)
       arr[ix] = values[i];

}

void main() {

   auto data = [7, 6, 5, 4, 3, 2, 1, 0];
   auto indexes = [6, 1, 1, 7];
   disjointSort(data, indexes);
   writeln(data);

}</lang> Output:

[7, 0, 5, 4, 3, 2, 1, 6]

F#

Translation of: Python

Works with arrays instead of lists because this algorithm is more efficient with a random access collection type. Returns a copy of the array, as is usually preferred in F#. <lang fsharp>let sortDisjointSubarray data indices =

 let indices = Array.sort indices
 let result = Array.copy data
 Array.map (Array.get data) indices
 |> Array.sort
 |> Array.iter2 (Array.set result) indices
 result


printfn "%A" (sortDisjointSubarray [|7;6;5;4;3;2;1;0|] [|6;1;7|])</lang>

Go

An example of sorting in place through the extra level of indirection. Compared to the strategy of extract-sort-reinsert, this strategy avoids the space overhead of the work area and the time overhead of extracting and reinserting elements. At some point however, the cost of indirection times O(log n) would dominate, and extract-sort-reinsert would become preferable. <lang go>package main

import (

   "fmt"
   "sort"

)

// type and methods satisfying sort.Interface type subListSortable struct {

   values  []int
   indices []int

}

func (s subListSortable) Len() int {

   return len(s.indices)

}

func (s subListSortable) Swap(i, j int) {

   s.values[s.indices[i]], s.values[s.indices[j]] =
       s.values[s.indices[j]], s.values[s.indices[i]]

}

func (s subListSortable) Less(i, j int) bool {

   return s.values[s.indices[i]] < s.values[s.indices[j]]

}

func main() {

   // givens
   values := []int{7, 6, 5, 4, 3, 2, 1, 0}
   indices := map[int]int{6:0, 1:0, 7:0}
   // make ordered list of indices for sort methods
   ordered := make([]int, len(indices))
   if len(indices) > 0 {
       i := 0
       for j := range indices {
           ordered[i] = j
           i++
       }
       sort.SortInts(ordered)
       // validate that indices are within list boundaries
       if ordered[0] < 0 {
           fmt.Println("Invalid index: ", ordered[0])
           return
       }
       if ordered[len(ordered)-1] >= len(values) {
           fmt.Println("Invalid index: ", ordered[len(ordered)-1])
           return
       }
   }
   // instantiate sortable type and sort
   s := subListSortable{values, ordered}
   fmt.Println("initial:", s.values)
   sort.Sort(s)
   fmt.Println("sorted: ", s.values)

}</lang> Output:

initial: [7 6 5 4 3 2 1 0]
sorted:  [7 0 5 4 3 2 1 6]

J

Note that the task requires us to ignore the order of the indices.

<lang j> 7 6 5 4 3 2 1 0 (/:~@:{`[`]}~ /:~) 6 1 7 7 0 5 4 3 2 1 6</lang>

Compare this with: <lang j> 6 1 7 /:~@:{`[`]} 7 6 5 4 3 2 1 0 7 1 5 4 3 2 0 6</lang>

Here, the order of the indices specifies the order we want the selected items to be sorted in: 7 1 5 4 3 2 0 6

Python

The function modifies the input data list in-place and follows the Python convention of returning None in such cases.

<lang python>>>> def sort_disjoint_sublist(data, indices): indices = sorted(indices) values = [data[i] for i in indices] values.sort() for index, value in zip(indices, values): data[index] = value


>>> d = [7, 6, 5, 4, 3, 2, 1, 0] >>> i = [6, 1, 7] >>> sort_disjoint_sublist(d, i) >>> d [7, 0, 5, 4, 3, 2, 1, 6]</lang>

Ruby

By convention, the exlamation mark in the method name indicates that something potentially dangerous can happen. (In this case, the in place modification). <lang ruby>def sort_disjoint_sublist!(ar, indices)

 values = ar.values_at(*indices).sort
 indices.sort.zip(values).each{ |i,v| ar[i] = v }
 ar

end

values = [7, 6, 5, 4, 3, 2, 1, 0] indices = [6, 1, 7] p sort_disjoint_sublist!(values, indices)</lang> Output

[7, 0, 5, 4, 3, 2, 1, 6]


Tcl

This returns the sorted copy of the list; this is idiomatic for Tcl programs where values are immutable. <lang tcl>package require Tcl 8.5 proc disjointSort {values indices args} {

   # Ensure that we have a unique list of integers, in order
   # We assume there are no end-relative indices
   set indices [lsort -integer -unique $indices]
   # Map from those indices to the values to sort
   set selected {}
   foreach i $indices {lappend selected [lindex $values $i]}
   # Sort the values (using any extra options) and write back to the list
   foreach i $indices v [lsort {*}$args $selected] {

lset values $i $v

   }
   # The updated list is the result
   return $values

}</lang> Demonstration: <lang tcl>set values {7 6 5 4 3 2 1 0} set indices {6 1 7} puts \[[join [disjointSort $values $indices] ", "]\]</lang> Output:

[7, 0, 5, 4, 3, 2, 1, 6]
Cookies help us deliver our services. By using our services, you agree to our use of cookies.