Sorting in Ruby by conditions - ruby

I have this array:
arr = [3, 8, 2, 13, 7]
I need to sort the elements first by the number of 1's of their bits and then by the decimal:
bits | decimal
-----+--------
10 | 2
11 | 3
0001 | 8
111 | 7
1011 | 13
to get the result:
[2, 3, 8, 7, 13]
I have this code:
arr = arr.sort { |x, y| x <=> y }
arr = arr.sort { |x, y| x.to_s(2).count(?1) <=> y.to_s(2).count(?1) }
arr # => [2, 8, 3, 13, 7]
How can I fix it?

arr.sort_by { |item| [item.to_s(2).count(?1), item] }
# => [2, 8, 3, 7, 13]
This contradicts the stated desired output, but I believe is consistent with the description of the problem (and that the stated desired output is incorrect): 2, 8 have 1 bit each, 3 has 2, 7 and 13 have 3 bits each; 2 comes before 8, 7 before 13.
This works because the default comparator for arrays is to compare them elementwise; e.g. for 2 and 8, the comparator is seeing [1, 2] <=> [1, 8]; since the first element is same, the second element is compared as a tiebreaker.
I took "decimal" to mean "the numeric value", as represented in OP's code; if it is to be taken literally as "the decimal representation", then
arr.sort_by { |item| [item.to_s(2).count(?1), item.to_s] }
# => [2, 8, 3, 13, 7]

Related

Arithmetic sequence Ruby

It is a code to find the missing sequence of an arithmetic sequence and finding common difference and also checking is it is an increasing or decreasing sequence. Take user input for further operation
For Ex: enter array elements
2 4 6 10 12 14
missing number is 8 instead of
enter array elements
2
4
6
10
12
14
missing number is 8
puts "enter arithmetic sequence"
o = Array.new
x = gets.chomp
item = x.split(" ")
o.push(item)
puts "#{o}"
len = o.length
sum = (len + 1) * (o[0] + o[len - 1]) / 2
summ = 0
o.each { |a| summ+=a }
res = sum - summ
if(o[1]>o[0])
puts "its an increasing sequence"
else
puts "its a decreasing sequence"
end
common_difference = o[1] - o[0]
puts "Common difference is #{common_difference}"
puts "missing number is #{res}"
The operations like sum common difference are working, but requirement is that we need to take user input in a single line instead of taking in multiple line, split that and store in an array.
For taking sum I used actual sum - target sum method.
Main issue is that it rise an error
`*': Array can't be coerced into Integer
How to convert array elements that is in string format to int using to_i method or Integer method
Expected Output
i/p 2 4 6 8 12 14
o/p
missing number 10
requirement is that we need to take user input in a single line instead of taking in multiple line, split that and store in an array
gets.chomp returns a string with trailing newline removed, e.g. (the 2nd line being user input)
x = gets.chomp
2 4 6 8 12 14
x #=> "2 4 6 8 12 14"
split converts that string to an array:
x.split
#=> ["2", "4", "6", "8", "12", "14"]
what's missing is the conversion to integer. To convert each element of an array, there's map:
x.split.map { |s| s.to_i }
#=> => [2, 4, 6, 8, 12, 14]
or its short-hand notation:
x.split.map(&:to_i)
#=> => [2, 4, 6, 8, 12, 14]
applied to your code:
puts "enter arithmetic sequence"
x = gets.chomp
o = x.split.map(&:to_i)
puts "#{o}"
# ...
Note that there's no need to create an empty array. You can just assign the result of map to o.
The rest of your code seems to work as expected. But you should check out Cary Swoveland's answer for more succinct way of finding the missing element.
Try this:
def missing_number(arr)
((arr.size + 1) * (arr.first + arr.last))/2 - arr.sum
end
missing_number [2, 4, 6, 10, 12, 14] #=> 8
missing_number [11, 8, 5, 2, -4, -7] #=> -1
missing_number [1.2, 2.0, 2.4, 2.8, 3.2] #=> 1.6000000000000014
Suppose arr were not missing any values. For example,
arr = [2, 4, 6, 8, 10, 12, 14]
Then:
arr.sum
#=> 56
which, because it is an arithmetic series, we could alternatively compute as follows:
(arr.size * (arr.first + arr.last))/2
#=> 56
In fact,
arr = [2, 4, 6, 10, 12, 14]
and
arr.sum
#=> 48
As I explained above, we can calculate the sum of the values of arr after the missing value has been inserted as follows:
((arr.size + 1) * (arr.first + arr.last))/2
#=> 56
The missing value therefore equals 56 - 48 #=> 8.
Here is another way to find the missing value that is slightly less efficient.
def missing_number(arr)
arr.each_cons(2).max_by { |a,b| (b-a).abs }.sum/2
end
missing_number [2, 4, 6, 10, 12, 14] #=> 8
missing_number [11, 8, 5, 2, -4, -7] #=> -1
missing_number [1.2, 2.0, 2.4, 2.8, 3.2] #=> 1.6
Suppose
arr = [11, 8, 5, 2, -4, -7]
The steps are as follows.
enum = arr.each_cons(2)
#=> #<Enumerator: [11, 8, 5, 2, -4, -7]:each_cons(2)>
We can see the (5) values that the enumerator will generate and pass to Enumerable#max_by by converting enum to an array:
enum.to_a
#=> [[11, 8], [8, 5], [5, 2], [2, -4], [-4, -7]]
Next let's look at the values that max_by will compare:
enum.map { |a,b| (b-a).abs }
#=> [3, 3, 3, 6, 3]
We therefore obtain the following:
c = enum.max_by { |a,b| (b-a).abs }
#=> [2, -4]
The last two steps calculate the average of 2 and -4:
d = c.sum
#=> -2
d/2
#=> -1

How to find the list of pairs in an array using ruby?

Input:
a = [4, 5, 5, 5, 6, 6, 4, 1, 4, 4, 3, 6, 6, 3, 6, 1, 4, 5, 5, 5]
How to list out no of pairs in an array.
Output:
9
Description
#no 1(1 pair)
#no 3(1 pair)
#no 4(2 pairs)
#no 5(3 pairs)
#no 6(2 pairs)
#so total 9 pairs
Here is another option:
a.group_by(&:itself).transform_values{ |v| v.size / 2 }.values.sum
#=> 9
How it works.
First group the elements by value:
a.group_by(&:itself) #=> {4=>[4, 4, 4, 4, 4], 5=>[5, 5, 5, 5, 5, 5], 6=>[6, 6, 6, 6, 6], 1=>[1, 1], 3=>[3, 3]}
Then transforming the keys to the pair count:
a.group_by(&:itself).transform_values{ |v| v.size / 2 } #=> {4=>2, 5=>3, 6=>2, 1=>1, 3=>1}
So, get the values of the hash:
a.group_by(&:itself).transform_values{ |v| v.size / 2 }.values #=> [2, 3, 2, 1, 1]
Finally, sum the values, which is the first line of code posted above.
arr = [4, 5, 5, 5, 6, 6, 4, 1, 4, 4, 3, 6, 6, 3, 6, 1, 4, 5, 5, 5]
hash = Hash.new(0)
arr.each { |e| hash[e] += 1 }
hash.values.reduce(0) { |s, n| s += n / 2 } // => 9
Since from what I can gather you are basically removing integers the moment they got paired once so technically it's just an integer division by two.
[1] How to count identical string elements in a Ruby array
[2] Reduce Hash Values
I have done like this, It works
b = []
a.uniq.each { |i| b.push(a.count(i)/2)}
b.sum

ruby find the index of the next available number

I have a find_num method that returns the index of a specified number in an ordered array, e.g.
find_num(6, [1, 4, 6, 9, 13]) #=> 2
however my spec also requires that if the number is not available it finds the position of the next highest number so ...
find_num(8, [1, 4, 6, 9, 13]) #=> 3
as 9 is the next available number.
Having trouble implementing this... I have thought of iterating through the whole array but I am told to take into account the array could be large...
You can pass a block to index and it ...
[...] returns the index of the first object for which the block returns true. Returns nil if no match is found.
Examples:
[1, 4, 6, 9, 13].index { |n| n >= 6 } #=> 2
[1, 4, 6, 9, 13].index { |n| n >= 8 } #=> 3
[1, 4, 6, 9, 13].index { |n| n >= 15 } #=> nil
Because this requires the array to be ordered, you can also use bsearch_index which performs a binary search.
you can also find a index of any element in array like this.
2.1.8 :040 > [1, 4, 6, 9, 13].index(6)
=> 2
2.1.8 :041 > [1, 4, 6, 9, 13].index(15)
=> nil
def find_num(n,a)
a.each_with_index.to_a.sort_by(&:first).find { |nbr,_| nbr >= n }.last
end
find_num(6, [1, 4, 6, 9, 13])
#=> 2
find_num(8, [1, 4, 6, 9, 13]) #=> 3
#=> 3
The steps for
n = 8
a = [1, 4, 6, 9, 13]
are as follows.
b = a.each_with_index.to_a
#=> [[1, 0], [4, 1], [6, 2], [9, 3], [13, 4]]
c = b.sort_by(&:first)
#=> [[1, 0], [4, 1], [6, 2], [9, 3], [13, 4]]
d = c.find { |nbr,_| nbr >= n }
#=> [9, 3]
d.last
#=> 3

Convert an array in ruby into an output stream

I have an array [2, 4, 6, 8, 3], i need to convert it into an output stream as below:
2 4 6 8 3
Converting into string and chopping the commas and quotes is not helping as it always prints as "2 4 6 8 3" if it is a string.
This is the input given:
5
2 4 6 8 3
This is the code i wrote
def insertionSort( ar)
key = ar.last
(ar.size-2).downto(0){
|x|
if(key < ar[x])
ar[x+1] = ar[x]
p ar
else
ar[x+1] = key
p ar
break
end
}
end
# Tail starts here
count = gets.to_i
ar = gets.strip.split.map {|i| i.to_i}
insertionSort( ar )
My Output:
[2, 4, 6, 8, 8]
[2, 4, 6, 6, 8]
[2, 4, 4, 6, 8]
[2, 3, 4, 6, 8]
Expected Outuput:
2 4 6 8 8
2 4 6 6 8
2 4 4 6 8
2 3 4 6 8
Test Result:
Fail
Your question isn't at all clear, but, maybe this is what you want:
ary = [2, 4, 6, 8, 3]
ary.join(' ') # => "2 4 6 8 3"
ary * ' ' # => "2 4 6 8 3"
Perhaps you don't understand how to loop?
ary = [2, 4, 6, 8, 3]
5.times do
puts ary.join(' ')
end
# >> 2 4 6 8 3
# >> 2 4 6 8 3
# >> 2 4 6 8 3
# >> 2 4 6 8 3
# >> 2 4 6 8 3
Or maybe you don't understand how command-line apps read STDIN?
Dealing with STDIN is useful when writing pipes: Chaining one small specialized application to another, and letting them collectively do a big task is the basic premise for *nix systems. Monolithic apps that try to do everything are a major PITA to write/maintain and use.
If you want to read a single line of input, either from STDIN or the keyboard, gets is good. If you want to read a series of lines, look at Ruby's ARGF class, and become very familiar with how STDIN and $stdin work.
Writing a Ruby command-line script is easy, but, just like doing it in Perl, Python or C, you have to be aware how the incoming data is accessed, what type of data it is (always a string), and how it's structured: characters terminated by a new-line ("\n") or carriage-return+new-line ("\r\n").
Perhaps you don't understand how to_i works?
"2 4 6 8 3".to_i # => 2
"24683".to_i # => 24683
"2_4_6_8_3".to_i # => 24683
to_i reads the string from the first character and continues until it finds a non-digit. So, in the above examples, 2 is the first digit in the first string, followed by a space. The space is a non-digit so to_i stops processing and only returns 2. In the second example, there are no spaces, so to_i processes the entire string and returns it as a single value. In the third, because Ruby, like some other languages, accepts _ as a part of a numeric string, to_i returns the full value again. _ is used to mark the comma positions in values, like 1_000_000.
As you write more code, take the time to write it clearly and cleanly. You want code that reduces the visual noise and makes it easy to take into your brain. Ruby makes it easy to write clean and expressive code that is easy to understand, but bad coding style can reduce Ruby code to unreadable quickly, especially to those of us who are used to seeing it written in an idiomatic style.
This isn't an attempt to fix your algorithm, it's just to show how you should style your code:
def insertion_sort(ar)
key = ar.last
(ar.size - 2).downto(0) { |x|
if (key < ar[x])
ar[x + 1] = ar[x]
p ar
else
ar[x + 1] = key
p ar
break
end
}
end
# Tail starts here
count = gets.to_i
ar = gets.strip.split.map { |i| i.to_i }
insertion_sort(ar)
Methods are always written in snake_case, never CamelCase.
Use whitespace; It gives your eyes and brain logical breaks that help define what is going on. Operators and control structures benefit from having whitespace before and after, and above and below.
Use spaces to indent, with tab-stops set to 2-spaces. This is the Ruby standard. Why those? Consistency as people move code between different editors; If you're working in a professional coding house you'll probably find a lot more rigid coding standards in place.
> a = [1, 2, 3, 4]
> puts "[#{a.join(', ')}]"
=> [1, 2, 3, 4]
Does not work on multi-dimensional arrays, or arrays within arrays.
> a = [1, 2, [3, 4, 5, 6], [7, 8, 9]]
> puts "[#{a.join(', ')}]"
=> [1, 2, 3, 4, 5, 6, 7, 8, 9]
But, if you do this, it should work for multi-dimensional arrays:
Example 1:
> a = [1, 2, [3, 4, 5, 6], [7, 8, 9]]
> a.each do |sub_a|
> puts "[#{a.join(', ')}]"
> end
=> [1, 2, [3, 4, 5, 6], [7, 8, 9]]
Example 2:
> a = [1, [2, [3, 4, [5, 6, 7, 8], 9, 0]], 'x', 'y', 'z']
> a.each do |sub_a|
> puts "[#{a.join(', ')}]"
> end
=> [1, [2, [3, 4, [5, 6, 7, 8], 9, 0]], "x", "y", "z"]
After reading the HackerRank "Insertion Point" question you referenced, the input appears to be coming from stdin. If your code includes
s = gets
it will wait for you to enter a string. Suppose you enter 1 2 3 4 (no quotes). Then s will hold "1 2 3 4\n".
If you want to convert this to an array:
a = s.split # => ["1","2","3","4"]
If you want the elements of a to be integers, rather than strings:
a.map! {|e| e.to_i} # => [1,2,3,4]
which (since Ruby version 1.9) can also be written:
a.map!(&:to_i) # => [1,2,3,4]
The 'Ruby way' would be to chain these operations:
a = gets.split.map(&:to_i) # => [1,2,3,4]
Note that we don't need ! with map now.
If you want this array to be a row i of some (existing array) b
b[i] = a

How to multiply every other element of an array?

Let's say that I have an array like this:
[1,2,3,4,5,6,7]
how can I multiply every other number of this array except the first by 2
so my new array looks like this
[1,4,3,8,5,12,7]
You can use map and with_index:
[1,2,3,4,5,6,7].map.with_index{|v,i| i % 2 == 0 ? v : v * 2 }
# => [1, 4, 3, 8, 5, 12, 7]
[1,2,3,4,5,6,7].each_slice(2).flat_map{|k, l| [k, *(l * 2 if l)]}
# => [1, 4, 3, 8, 5, 12, 7]

Resources