Sort 3-tuple - idiomatic code?


#1

Hi, Just starting with rust and I needed to sort a tuple of 3 ints eg (3,2,1) -> (1,2,3). I wrote a general function like this

pub fn sort<T: Eq + Ord + Clone>(tpl: (T, T, T) ) -> (T, T, T){
let (a, b, c) = tpl;
let mut v = vec![a, b, c];
v.sort();

(v[0].clone(), v[1].clone(), v[2].clone())

}

The above works but is it idiomatic Rust? Also if I remove v[0].clone() etc then I get the error “cannot move out of indexed content” . Is clone() the way to fix the error?

Thanks

Mike


#2

Yes, clone() is the right fix.

If the type is Copy (all primitive ints are), you don’t need to clone() it, and you would use fn sort<T: Eq + Ord + Copy> instead. That being said, if you want to remain more generic, then clone() is fine – for simple Copy types like ints, it will be identical to Copying the bits over.

Also, if you use an array (stack-allocated) instead of the Vec (let mut v = [a, b, c];), you can avoid a heap allocation.

pub fn sort<T: Eq + Ord + Copy>(tpl: (T, T, T) ) -> (T, T, T){
  let (a, b, c) = tpl;
  let mut v = [a, b, c];
  v.sort();
  let [a, b, c] = v;
  (v[0], v[1], v[2])
}

Playground

Once the experimental slice pattern syntax on nightly is implemented (IMO) correctly, you could be even more generic by using only moves instead of copies and require no Copy/Clone type constraints.

#![feature(slice_patterns)]

pub fn sort<T: Eq + Ord>(tpl: (T, T, T) ) -> (T, T, T){
  let (a, b, c) = tpl;
  let mut v = [a, b, c];
  v.sort();
  let [a, b, c] = v;
  (a, b, c)
}

But that fails currently because it thinks the let binding is moving out of v three possibly overlapping times.


#3

Just a couple of questions:

  • Do you need the inputs and outputs to be tuples? An array would seem more appropriate for this use case of homogeneous data.
  • Speaking of arrays, why are you using a vec here when an array would suffice?
  • As this looks like homework, are you sure that you are allowed to use the sort() function here, and not expected to implement the sort yourself?

#4

Huh…it…did not occur to me that this could be homework.


#5

Just emitting this assumption because I could not think of a normal situation in which someone would need to sort 3-tuples of homogeneous data :slight_smile:


#6

You can use remove instead of clone


#7

Thanks all. marcianx in particular.
No it is not homework! I’ve 30 years pro software developer, mainly Java, then three of years Haskell and ten hours Rust.
Homework is no longer a concern :slight_smile:

Mike


#8

Except for the case of wanting to sort a 3- tuple of homogenous data if only to play with the types.


#9

My mistake!


#10

I have done such a thing before to have sets of homogeneous tuples, where the order in the tuple is actually irrelevant to me. Just for the sake of comparison and deduplication, I normalized the tuples to be sorted first.

I confess it didn’t occur to me to use the built-in slice sort for so few items. I just open-coded a bubble sort, something like:

if x.0 > x.1 { mem::swap(&mut x.0, &mut x.1); }
if x.1 > x.2 { mem::swap(&mut x.1, &mut x.2); }
if x.0 > x.1 { mem::swap(&mut x.0, &mut x.1); }

(and a tuple was slightly preferable over a [T; 3] just because of pattern matching)