# Feeling sharp? Sort an array subset in place

**URL:** <https://www.ruby-forum.com/t/feeling-sharp-sort-an-array-subset-in-place/101930>\
**Category:** Ruby\
**Created:** [February 7, 2006, 9:29am UTC](https://www.ruby-forum.com/t/feeling-sharp-sort-an-array-subset-in-place/101930 "2006-02-07T09:29:44Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![bluetrust](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8e7dd6/32.png) [@bluetrust](https://www.ruby-forum.com/u/bluetrust)\
**Post date:** [February 7, 2006, 9:29am UTC](https://www.ruby-forum.com/t/feeling-sharp-sort-an-array-subset-in-place/101930/1 "2006-02-07T09:29:44Z")

</div>

Here’s the situation: I have an array and I’d like to sort certain  
elements in place – without touching the others.

Unsorted array contents:  
3 \<-- sort me!  
x  
1 \<-- sort me!  
y  
2 \<-- sort me!

Sorted array contents  
1  
x  
2  
y  
3

See how 1, 2, and 3 played musical chairs? That’s exactly what we  
want. It seems like there should be an easy one, two or three-line way  
to do this given an array and a test condition (for identifying  
elements which need sorting.)

How would you do it?

(My solution was a dirty cheat, it involved building a hash of {from =\>  
to} moves, cloning the original array contents, then changing each  
element one at a time. Blah. There’s got to be a sexier way.)

---

<div class="post-metadata">

**Author:** ![bluetrust](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8e7dd6/32.png) [@bluetrust](https://www.ruby-forum.com/u/bluetrust)\
**Post date:** [February 7, 2006, 10:18am UTC](https://www.ruby-forum.com/t/feeling-sharp-sort-an-array-subset-in-place/101930/2 "2006-02-07T10:18:14Z")

</div>

On Tue, Feb 07, 2006 at 05:28:21PM +0900, Michael J. wrote:

> Sorted array contents  
> 1  
> x  
> 2  
> y  
> 3

class Array  
def sort\_subset!  
els, indices = [], []  
each\_with\_index{|x,i| (els \<\< x; indices \<\< i) if yield(x) }  
els.sort.each\_with\_index{|x,i| self[indices[i]] = x}  
end  
end

a = (0…10).sort\_by{rand}  
a # =\> [1, 8, 2, 10, 3,  
0, 5, 4, 9, 7, 6]  
a.sort\_subset!{|x| x % 2 == 0} # =\> [0, 2, 4, 6, 8,  
10]  
a # =\> [1, 0, 2, 4, 3,  
6, 5, 8, 9, 7, 10]  
a.sort\_subset!{|x| x % 2 == 1} # =\> [1, 3, 5, 7, 9]  
a # =\> [1, 0, 2, 4, 3,  
6, 5, 8, 7, 9, 10]

---

<div class="post-metadata">

**Author:** ![bluetrust](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8e7dd6/32.png) [@bluetrust](https://www.ruby-forum.com/u/bluetrust)\
**Post date:** [February 7, 2006, 10:21am UTC](https://www.ruby-forum.com/t/feeling-sharp-sort-an-array-subset-in-place/101930/3 "2006-02-07T10:21:18Z")

</div>

Michael J. wrote:

> Sorted array contents
> 
> How would you do it?
> 
> (My solution was a dirty cheat, it involved building a hash of {from =\>  
> to} moves, cloning the original array contents, then changing each  
> element one at a time. Blah. There’s got to be a sexier way.)

a = [3, :x, 1, :y, 2]  
f=nil  
tmp = a.partition{ f=!f }  
p tmp.first.sort.zip( tmp.last ).flatten.compact

---

<div class="post-metadata">

**Author:** ![bluetrust](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8e7dd6/32.png) [@bluetrust](https://www.ruby-forum.com/u/bluetrust)\
**Post date:** [February 7, 2006, 10:24am UTC](https://www.ruby-forum.com/t/feeling-sharp-sort-an-array-subset-in-place/101930/4 "2006-02-07T10:24:20Z")

</div>

Michael J. wrote:

> Sorted array contents
> 
> How would you do it?

I’d change the app design to not have these arrays. Seriously. It  
seems  
as if you were storing things together that do not belong together. Why  
do you need that?

Kind regards

```
robert

```

irb(main):001:0\> a=[3,“y”,1,“x”,2]  
=\> [3, “y”, 1, “x”, 2]  
irb(main):002:0\> s=a.select {|x| Integer === x}.sort  
=\> [1, 2, 3]  
irb(main):003:0\> i=0  
=\> 0  
irb(main):004:0\> a.map! {|e| Integer === e ? (r=s[i]; i+=1; r) : e}  
=\> [1, “y”, 2, “x”, 3]

---

<div class="post-metadata">

**Author:** ![bluetrust](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8e7dd6/32.png) [@bluetrust](https://www.ruby-forum.com/u/bluetrust)\
**Post date:** [February 7, 2006, 10:30am UTC](https://www.ruby-forum.com/t/feeling-sharp-sort-an-array-subset-in-place/101930/5 "2006-02-07T10:30:26Z")

</div>

Michael J. wrote:

> Sorted array contents
> 
> How would you do it?

I’m definitely _not_ feeling sharp (10 AM here and I haven’t slept yet)  
but here’s my try:

arr = [3,:x,1,:y,2] # =\> [3, :x, 1, :y, 2]  
sorted = arr.select { |v| v.class == Fixnum }.sort # =\> [1, 2, 3]  
arr.map { |v| v.class == Fixnum ? sorted.shift : v } # =\> [1, :x, 2,  
:y, 3]

Of course, substitute conditions as appropriate.

- Peter

---

<div class="post-metadata">

**Author:** ![bluetrust](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8e7dd6/32.png) [@bluetrust](https://www.ruby-forum.com/u/bluetrust)\
**Post date:** [February 7, 2006, 3:13pm UTC](https://www.ruby-forum.com/t/feeling-sharp-sort-an-array-subset-in-place/101930/6 "2006-02-07T15:13:00Z")

</div>

On Tue, 2006-02-07 at 17:28 +0900, Michael J. wrote:

> Here’s the situation: I have an array and I’d like to sort certain  
> elements in place – without touching the others.

I agree with Robert that you should probably think about why your data  
is kept this way. But here’s one I’ve used:

```
class Array
  def select_sort!(sort_proc = nil)
    t = []
    map! { |x| if yield x then t << x; nil else x end }
    t.sort!(&sort_proc)
    map! { |x| x or t.shift }
  end
end

```

Which works like:

a = [2,‘a’,3,‘b’,‘c’,1]

> > # =\> [2, “a”, 3, “b”, “c”, 1]

a.select\_sort! { |x| x.is\_a? Fixnum }

> > p a

# =\> [1, “a”, 2, “b”, “c”, 3]

a.select\_sort!(lambda { |x,y| y \<=\> x }) { |x| x.is\_a? Fixnum }

> > p a

# =\> [3, “a”, 2, “b”, “c”, 1]

But it breaks down if your array contains nil elements beforehand, and  
has that nasty two-block look about it.
