How to sort array ascending, except zero ?

P

Paganoni

Hello, I need to sort
[1,4,2,0,8,9] to [1,2,4,8,9,0]

A simple ascending sort but with the zero values to the end

I really don't see how to do

Thanks for your help
 
A

Andrew Timberlake

Hello, I need to sort
[1,4,2,0,8,9] to [1,2,4,8,9,0]

A simple ascending sort but with the zero values to the end

I really don't see how to do

Thanks for your help

Maybe not the most elegant solution but it gets the job done:
arr = [1,4,2,0,8,9]
arr = (arr - [0]).sort << 0

Otherwise you want to override <=> on Fixnum

Andrew Timberlake
http://ramblingsonrails.com

http://MyMvelope.com - The SIMPLE way to manage your savings
 
M

Martin DeMello

Hello, I need to sort
[1,4,2,0,8,9] to [1,2,4,8,9,0]

A simple ascending sort but with the zero values to the end

max = a.max + 1
# or max = 2 ** 31, say, if you don't want the extra pass
# but sorting is O(n log n) and max is O(n) so it doesn't really matter

a.sort_by {|x| x.zero? ? max : x}

martin
 
R

Robert Klemme

2009/6/8 Andrew Timberlake said:
Hello, I need to sort
[1,4,2,0,8,9] to [1,2,4,8,9,0]

A simple ascending sort but with the zero values to the end
Otherwise you want to override <=> on Fixnum

Definitively not! Changing the default Fixnum ordering is dangerous
because it will likely break a lot of other code and it is
superfluous, too. There are better tools for that, i.e. defining the
sort order in the place where it is needed (see Martin's solution).

Kind regards

robert
 
R

Robert Klemme

2009/6/8 Martin DeMello said:
Hello, I need to sort
[1,4,2,0,8,9] to [1,2,4,8,9,0]

A simple ascending sort but with the zero values to the end

max = a.max + 1
# or max = 2 ** 31, say, if you don't want the extra pass
# but sorting is O(n log n) and max is O(n) so it doesn't really matter

Still traversing the array twice just to get the max beforehand does
not /feel/ right. I'd rather use your "large constant" - maybe even
with a _really_ large number: :)

irb(main):020:0> a = [1,4,2,0,8,9]
=> [1, 4, 2, 0, 8, 9]
irb(main):021:0> INF = 1.0 / 0.0
=> Infinity
irb(main):022:0> a.sort_by {|x| x == 0 ? INF : x}
=> [1, 2, 4, 8, 9, 0]

Another good alternative is to use the block form of #sort:

irb(main):023:0> a.sort do |x,y|
irb(main):024:1* case
irb(main):025:2* when x == 0 then 1
irb(main):026:2> when y == 0 then -1
irb(main):027:2> else x <=> y
irb(main):028:2> end
irb(main):029:1> end
=> [1, 2, 4, 8, 9, 0]

Kind regards

robert
 
M

Martin DeMello

Still traversing the array twice just to get the max beforehand does
not /feel/ right. =A0I'd rather use your "large constant" - maybe even
with a _really_ large number: :)

irb(main):020:0> a =3D [1,4,2,0,8,9]
=3D> [1, 4, 2, 0, 8, 9]
irb(main):021:0> INF =3D 1.0 / 0.0
=3D> Infinity

Ah yes, forgot you could compare floats with fixnums :)

martin
 
B

Bertram Scharpf

Hi,

Am Montag, 08. Jun 2009, 17:40:06 +0900 schrieb Paganoni:
Hello, I need to sort
[1,4,2,0,8,9] to [1,2,4,8,9,0]
A simple ascending sort but with the zero values to the end

I don't know what you want to do further with the sorted values
but maybe this is an approach to consider:

s = a.map { |x| x.nonzero? }
s.compact!
s.sort!

or

s, z = a.map { |x| x.nonzero? }.partition { |x| x }
s.sort!
puts z.length

Bertram


P.S.: Still, my opinion is that there should be an equivalent
String#notempty? to Numeric#nonzero? !
 
H

Harry Kakueki

Hello, I need to sort
[1,4,2,0,8,9] to [1,2,4,8,9,0]

A simple ascending sort but with the zero values to the end

I really don't see how to do

Thanks for your help



tmp = arr.partition{|x| x != 0 }
(tmp[0].sort + tmp[1])

Harry
 
H

Harry Kakueki

Hello, I need to sort
[1,4,2,0,8,9] to [1,2,4,8,9,0]

A simple ascending sort but with the zero values to the end

I really don't see how to do

Thanks for your help



tmp = arr.partition{|x| x != 0 }
(tmp[0].sort + tmp[1])

Harry

Oops!

tmp = arr.partition{|x| x != 0 }
p (tmp[0].sort + tmp[1])

The second line should be like this, of course.

Harry
 
P

Paganoni

le 08/06/2009 10:38, Paganoni nous a dit:
Hello, I need to sort
[1,4,2,0,8,9] to [1,2,4,8,9,0]

A simple ascending sort but with the zero values to the end

I really don't see how to do

Thanks for your help

I forgot to mention that the array can contain several 0 values not only
one.
 
G

Giampiero Zanchi

ciao
if you are sure not to have negative numbers in your input, then you can
map each number to its negative, sort descending and then map again to
positive
 
G

Giampiero Zanchi

Giampiero said:
ciao
if you are sure not to have negative numbers in your input, then you can
map each number to its negative, sort descending and then map again to
positive

sorry; it cannot work, of course
 
M

Martin DeMello

le 08/06/2009 10:38, Paganoni nous a dit:
I forgot to mention that the array can contain several 0 values not only
one.

My solution took that into account. Give it a try.

martin
 
A

andrea

Robert Klemme said:
Another good alternative is to use the block form of #sort:

irb(main):023:0> a.sort do |x,y|
irb(main):024:1* case
irb(main):025:2* when x == 0 then 1
irb(main):026:2> when y == 0 then -1
irb(main):027:2> else x <=> y
irb(main):028:2> end
irb(main):029:1> end
=> [1, 2, 4, 8, 9, 0]

isn't this simplified version fine too?

irb(main):003:0> a=[0,3,2,-5,0,4]
=> [0, 3, 2, -5, 0, 4]
irb(main):004:0> a.sort{|x,y| x.zero? ? 1 : x<=>y}
=> [-5, 2, 3, 4, 0, 0]
 
M

Michael Neumann

Paganoni said:
le 08/06/2009 10:38, Paganoni nous a dit:
Hello, I need to sort
[1,4,2,0,8,9] to [1,2,4,8,9,0]

A simple ascending sort but with the zero values to the end

I really don't see how to do

Thanks for your help

I forgot to mention that the array can contain several 0 values not only
one.

Infinity = 1.0/0.0

[1,4,2,0,8,9].sort_by {|x| x == 0 ? Infinity : x }

Or:

a = [1,4,2,0,8,9]
max = a.max + 1
a.sort_by {|x| x == 0 ? max : x }

Regards,

Michael
 
R

Robert Klemme

Robert Klemme said:
Another good alternative is to use the block form of #sort:

irb(main):023:0> a.sort do |x,y|
irb(main):024:1* case
irb(main):025:2* when x == 0 then 1
irb(main):026:2> when y == 0 then -1
irb(main):027:2> else x <=> y
irb(main):028:2> end
irb(main):029:1> end
=> [1, 2, 4, 8, 9, 0]

isn't this simplified version fine too?

irb(main):003:0> a=[0,3,2,-5,0,4]
=> [0, 3, 2, -5, 0, 4]
irb(main):004:0> a.sort{|x,y| x.zero? ? 1 : x<=>y}
=> [-5, 2, 3, 4, 0, 0]

irb(main):003:0> a=[1,0]
=> [1, 0]
irb(main):004:0> a.sort{|x,y| x.zero? ? 1 : x<=>y}
=> [0, 1]
irb(main):005:0>

Not what the OP wanted.

Cheers

robert
 
B

brabuhr

irb(main):003:0> a=[0,3,2,-5,0,4]
=> [0, 3, 2, -5, 0, 4]
irb(main):004:0> a.sort{|x,y| x.zero? ? 1 : x<=>y}
=> [-5, 2, 3, 4, 0, 0]

irb(main):003:0> a=[1,0]
=> [1, 0]
irb(main):004:0> a.sort{|x,y| x.zero? ? 1 : x<=>y}
=> [0, 1]
irb(main):005:0>

Assuming a stable sorting algorithm, sort twice is an option:

irb(main):001:0> [1, 0].sort.sort_by{|n| n.zero? ? 1 : 0}
=> [1, 0]
irb(main):002:0> [0,3,2,-5,0,4].sort.sort_by{|n| n.zero? ? 1 : 0}
=> [-5, 4, 3, 2, 0, 0]
irb(main):003:0> a = (1..10).map{|n| rand(5) - 2}
=> [-1, 2, -1, 0, 0, 2, 0, 2, 2, -2]
irb(main):004:0> a.sort.sort_by{|n| n.zero? ? 1 : 0}
=> [-2, -1, -1, 2, 2, 2, 2, 0, 0, 0]
irb(main):033:0> a.sort.sort_by{|n| n.zero?.to_s}
=> [-2, -1, -1, 2, 2, 2, 2, 0, 0, 0]
 
R

Robert Klemme

irb(main):003:0> a=[0,3,2,-5,0,4]
=> [0, 3, 2, -5, 0, 4]
irb(main):004:0> a.sort{|x,y| x.zero? ? 1 : x<=>y}
=> [-5, 2, 3, 4, 0, 0]
irb(main):003:0> a=[1,0]
=> [1, 0]
irb(main):004:0> a.sort{|x,y| x.zero? ? 1 : x<=>y}
=> [0, 1]
irb(main):005:0>

Assuming a stable sorting algorithm, sort twice is an option:

irb(main):001:0> [1, 0].sort.sort_by{|n| n.zero? ? 1 : 0}
=> [1, 0]

Sorting twice only to make the block to sort simpler does not sound like
a good operation.

Kind regards

robert
 
B

brabuhr

Assuming a stable sorting algorithm, sort twice is an option:

irb(main):001:0> [1, 0].sort.sort_by{|n| n.zero? ? 1 : 0}
=> [1, 0]

Sorting twice only to make the block to sort simpler does not sound like
a good operation.

Especially the to_s version :)

Error: Your application used more memory than the safety cap of 500m.
Specify -J-Xmx####m to increase it (#### = cap size in MB).
Specify -w for full OutOfMemoryError stack trace

require 'benchmark'
Infinity = 1.0/0.0
Benchmark.bm(25) do |b|
a = (1..500000).map{|n| rand(10) - 20}
b.report("A") {
a.sort.sort_by{|n| n.zero? ? 1 : 0}
}
b.report("B") {
a.sort_by {|x| x == 0 ? Infinity : x }
}
b.report("C") {
max = a.max + 1
a.sort_by {|x| x == 0 ? max : x }
}
b.report("D") {
tmp = a.partition{|x| x != 0 }
tmp[0].sort + tmp[1]
}
b.report("E") {
a.sort do |x,y|
case
when x == 0 then 1
when y == 0 then -1
else x <=> y
end
end
}
end

Linux 2.6.28-11-generic #42-Ubuntu SMP Fri Apr 17 01:57:59 UTC 2009
i686 GNU/Linux

ruby 1.8.7 (2008-08-11 patchlevel 72) [i486-linux]
user system total real
A 1.070000 0.160000 1.230000 ( 1.320943)
B 1.290000 0.140000 1.430000 ( 1.691468)
C 1.530000 0.200000 1.730000 ( 2.863440)
D 0.750000 0.180000 0.930000 ( 1.323304)
E 3.840000 0.400000 4.240000 ( 5.043411)

ruby 1.9.0 (2008-06-20 revision 17482) [i486-linux]
user system total real
A 0.470000 0.020000 0.490000 ( 0.522487)
B 0.550000 0.010000 0.560000 ( 0.631449)
C 0.640000 0.000000 0.640000 ( 0.692639)
D 0.230000 0.020000 0.250000 ( 0.279466)
E 0.820000 0.000000 0.820000 ( 0.870455)

jruby 1.3.0 (ruby 1.8.6p287) (2009-06-03 5dc2e22) (OpenJDK Client VM
1.6.0_0) [i386-java]
user system total real
A 1.664000 0.000000 1.664000 ( 1.617000)
B 2.315000 0.000000 2.315000 ( 2.316000)
C 2.536000 0.000000 2.536000 ( 2.536000)
D 0.772000 0.000000 0.772000 ( 0.772000)
E 5.175000 0.000000 5.175000 ( 5.175000)
 
S

Sebastian Hungerecker

Am Montag 08 Juni 2009 20:55:17 schrieb (e-mail address removed):
Assuming a stable sorting algorithm

Neither sort nor sort_by use a stable sorting algorithm though.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,521
Members
44,995
Latest member
PinupduzSap

Latest Threads

Top