ray
ray

Reputation: 661

Ruby Array not sorting

I am trying to sort an array, but it always returns the same original input. Do you know why?

puts "Please tell me the array(separated by space, finish by enter twice):"
x = []
input = ' '
while input != ''
  input = gets.chomp
  x.push input
end

puts x.sort

Upvotes: 2

Views: 594

Answers (6)

Stefan
Stefan

Reputation: 114188

Your code expects the items to be entered on separate lines. An easy "fix" is to adjust the help message:

puts "Please tell me the array (one item per line, finish by enter twice)"

And to provide the items as expected:

$ ruby sort.rb
Please tell me the array (one item per line, finish by enter twice)
b
c
a


a
b
c

Note that your code adds the empty line to the array. This can be fixed by checking input:

x = []
input = ' '
while input != ''
  input = gets.chomp
  x.push input unless input.empty?
end

Having to check for an empty input twice (input != '' / input.empty?) and the random initial value (input = ' ') can be avoided by using loop and break instead of while:

x = []
loop do
  input = gets.chomp
  break if input.empty?
  x.push input
end

Upvotes: 1

Hernan Velasquez
Hernan Velasquez

Reputation: 2820

If you are expecting to sort an array of numbers, change this line:

x.push input.to_i

Otherwise an input like:

4
10
1

Will be ordered:

1
10
4

If you are expecting strings, your program should work and more details should be provided.

Upvotes: 0

the Tin Man
the Tin Man

Reputation: 160551

Meditate on this:

x = [] # => []
input = '1 2 3' # => "1 2 3"
x.push input # => ["1 2 3"]
x.sort # => ["1 2 3"]

Basically, you're entering a single string in your code, pushing it into the array, then sorting a single element array. That's not going to do anything since you can't sort a single element array and get a different order. (Well, you can expect it to be different, but it won't be.)

Instead:

x = [] # => []
x.push '1' # => ["1"]
x.push '3' # => ["1", "3"]
x.push '2' # => ["1", "3", "2"]

That simulates entering three different strings. Sorting x now returns a sorted array:

x.sort  # => ["1", "2", "3"]

Here's something else to meditate on:

require 'fruity'

string = ('a'..'z').to_a.join(' ')
string # => "a b c d e f g h i j k l m n o p q r s t u v w x y z"

3.times do
  compare do
    split1 { string.split }
    split2 { string.split(' ') }
    split3 { string.split(/\s/) }
    split4 { string.split(/\s+/) }
  end
end

# >> Running each test 1024 times. Test will take about 1 second.
# >> split1 is faster than split2 by 10.000000000000009% ± 10.0%
# >> split2 is faster than split3 by 3x ± 0.1
# >> split3 is similar to split4
# >> Running each test 2048 times. Test will take about 1 second.
# >> split1 is faster than split2 by 10.000000000000009% ± 10.0%
# >> split2 is faster than split3 by 3x ± 0.1
# >> split3 is similar to split4
# >> Running each test 1024 times. Test will take about 1 second.
# >> split1 is faster than split2 by 10.000000000000009% ± 10.0%
# >> split2 is faster than split3 by 3x ± 0.1
# >> split3 is similar to split4

The results for split1 and split2 are about 10% in favor of split1 so sometimes Fruity reports a 10% difference and sometimes it doesn't. The same is true for split3 and split4.

And:

string = ('a'..'z').to_a.zip(26.times.map{ ' ' * (rand(4) + 1)}).join
string # => "a    b  c    d    e  f   g  h   i j  k l  m    n  o  p q r    s   t   u  v w  x    y z    "
compare do
  split1 { string.split }
  split2 { string.split(' ') }
  split3 { string.split(/\s/) }
  split4 { string.split(/\s+/) }
end

# >> Running each test 1024 times. Test will take about 1 second.
# >> split1 is similar to split2
# >> split2 is faster than split4 by 3x ± 0.1
# >> split4 is faster than split3 by 2.1x ± 0.1 (results differ: ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"] vs ["a", "", "", "", "b", "", "c", "", "", "", "d", "", "", "", "e", "", "f", "", "", "g", "", "h", "", "", "i", "j", "", "k", "l", "", "m", "", "", "", "n", "", "o", "", "p", "q", "r", "", "", "", "s", "", "", "t", "", "", "u", "", "v", "w", "", "x", "", "", "", "y", "z"])

The last result is different because split(/\s/) is only looking for single whitespace characters, not multiples like split(/\s+/) does. I left that result in to show the different the + can make to the engine.

Upvotes: 2

Andrey Deineko
Andrey Deineko

Reputation: 52357

Use String#split. Take a look:

 x = '1 3 2 4 55'
 x.split.sort
 #=> ["1", "2", "3", "4", "55"]

If x is an array of strings, you can do the following:

x = ['1 3 100', '2 30 4 10']
x.flat_map { |string| string.split }.sort
#=> ["1", "10", "100", "2", "3", "30", "4"] Note it is sorted alphabetically.

If you want to sort input numerically consider this:

x = ['1 3 100', '2 30 4 10']
x.flat_map { |string| string.split.map(&:to_i) }.sort
#=> [1, 2, 3, 4, 10, 30, 100]

Though in real life I would prefer @tadman's solution, because it operates on the input immediately, unifying it.

Upvotes: 3

tadman
tadman

Reputation: 211610

You need to both split the input and concat to a singular array:

x = [ ]

loop do
  input = gets.chomp

  break if (input.empty?)

  x += input.split
end

puts x.sort

Upvotes: 6

Philip Hallstrom
Philip Hallstrom

Reputation: 19879

If you're entering all the numbers on a single line then you only need one call to gets. See the below. We read a single line of input, split the input on any number of spaces and convert the values to their integer form. Then we display them sorted.

$ cat foo.rb
puts "Please tell me the array(separated by space, finish by enter twice):"
input = gets.chomp
x = input.split(/\s+/).map(&:to_i)
puts x.sort


$ ruby foo.rb
Please tell me the array(separated by space, finish by enter twice):
2423 888 3333 222
222
888
2423
3333

Upvotes: 1

Related Questions