2

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
2
  • 3
    Can you provide an example of your input and output that shows the problem? Commented Sep 14, 2015 at 18:04
  • i used "2423 888 3333 222", and the result is still "2423 888 3333 222" @PhilipHallstrom Commented Sep 14, 2015 at 18:12

6 Answers 6

6

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
Sign up to request clarification or add additional context in comments.

4 Comments

I think this is the best solution. +1
Just as a reminder: split is the equivalent of split(/\s+/).
@theTinMan Good point. The less regex-ular this is the better. Updated accordingly.
I just added a simple benchmark comparing different ways to split. It's enlightening.
3

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.

4 Comments

x is an array, not a string. You're on the right track though.
@ray, this is the solution to your problem, if you are expecting to receive a string with words separated by spaces. +1
Closer, but still not there. You're sorting arrays, not individual elements. flat_map or .flatten would fix that.
Note: split is the equivalent of split(' ').
2

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.

Comments

1

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

1 Comment

This only allows one line of input.
1

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

Comments

0

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.

2 Comments

I am expecting strings, but it just won't sort :(. for example, "2 aa c b a 9 7 8" , after sorting, still "2 aa c b a 9 7 8" @hernanvelasquez
oh I see. Look at Andrey's answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.