Scope of variable

please help me to solve the error during selection sorting due to change in scope of the variable

for  i in 0..array.len()
    {
        position = i;
        for j in (i+1)..array.len()-1
        {
            if array[position] > array[j]
            {
                 position =j;
            }
        }
        if position != i
        {
            swap = array[i];
            array[i] = array[j];
            array[j] = swap;
        }
    }


/* error:cannot find value `j` in this scope*/

how to solve this using reference and borrowing or using any other method?

Scope of iteration variables is limited the for loop, and there's no way to get them outside of the for loop.

You'll have to use

let j = i+1; 
while j < array.len()-1 {
}

to use j outside of the loop.

Even if you could, j would have the last value of the loop -- is that really what you want? It looks like you mean to act on the position index.

Also, slices have an easy swap method, which you can use on arrays and Vec too.

2 Likes

any other solution like using reference and borrowing

It's hard to advise more idiomatic Rust code here, because I assume you're deliberately writing bubble sort. It's a poor algorithm, and it doesn't have an elegant way to express in Rust.

for i in array.len() loops are generally discouraged in Rust (they're slower than for element in array), but in your case you have two nested loops that need to mutate elements, so doing it with iterators makes it tricky. The inner loop could use a slice from split_at_mut(i+1), and use mem::swap to swap elements.

If you want to practice Rust on simple problems, try https://exercism.io/tracks/rust

1 Like

Just a nit: this is actually selection sort with a minor bug that the compiler caught for you: the final swap was supposed to be between positions i and position (as noted by @cuviper) which should get rid of the error. :wink:

I'm sure there are multiple ways to write a rust-ier solution. Here's one:

Edit: Actually, look at the one 2 posts down which is a bit easier to read.

fn selection_sort(mut array: &mut [u32]) {
    // Instead of an index going through the array,
    // we will keep shrinking the array slice down
    // to its unsorted portion.
    while array.len() > 0 {
        // Find the (index, value) with the min
        // value in the remaining slice.
        let min_val_pos = array
            .iter().copied().enumerate()
            .min_by_key(|&(_index, val)| val);
            
        if let Some((min_pos, _)) = min_val_pos {
            array.swap(0, min_pos);
        }

        array = &mut array[1..];
    }
}

Playground

1 Like

Can't blame anyone for not recognizing the sort algorithm here. It's operation is obscured by all that functional programming junk.

I'm not sure I understand the criticism. Presumably you're not criticizing the the one in the original post – the one that wasn't recognized as selection sort?

If you are referring to the example I wrote above, I completely understand that style is unfamiliar to some and an immediate turn-off. However, it was written to actually read like the description of the Selection Sort algorithm (bullets are mine to emphasize the 3 steps):

The algorithm proceeds by

  1. finding the smallest (or largest, depending on sorting order) element in the unsorted sublist,
  2. exchanging (swapping) it with the leftmost unsorted element (putting it in sorted order), and
  3. moving the sublist boundaries one element to the right.

Those are exactly the 3 lines I wrote above. In this form, it doesn't require complicated reasoning about the presence of off-by-one errors, which I often have to do with in-place sorts written in the style I would in C.

Perhaps this slightly modified version emphasizes a bit better that the first line computes the index of the min.

fn selection_sort(mut array: &mut [u32]) {
    // Instead of an index going through the array,
    // we will keep shrinking the array slice down
    // to its unsorted portion.
    while array.len() > 0 {
        let index_of_min = array
            .iter().copied().enumerate()
            .min_by_key(|&(_index, val)| val)
            .map(|(index, _val)| index);
            
        if let Some(index_of_min) = index_of_min {
            array.swap(0, index_of_min);
        }

        array = &mut array[1..];
    }
}

Playground

1 Like

marcianx

Sorry yes, I was getting my snippets mixed up.

Don't mind me, I have been programming with real variables, arrays, indices and loops for so long that I have a hard time following along when everything disappears and is hidden behind behind words in the modern functional style.

Hopefully I'll get comfortable with it with enough practice.