Insert after every nth comma in a string [duplicate] - ruby-on-rails

This question already has answers here:
Inserting an array into every nth element of another
(3 answers)
Closed 6 years ago.
I have the following string and array:
a = '1, 2, 3, 4, 5, 6, 7, 8'
b = ['9', '10', '11', '12']
I need to insert an element of b after every nth comma (2 for this example) into a, resulting in:
a = '1, 2, 9, 3, 4, 10, 5, 6, 11, 7, 8, 12'
I've been playing around with various forms of scan but can't seem to produce the desired result.
Is there an easy way for me to do this?

Use a.split(', '), any solution from your previous question, and join(', ').
With credits to #Stefan :
a = '1, 2, 3, 4, 5, 6, 7, 8'
b = ['9', '10', '11', '12']
enum = Enumerator.new do |y|
e1 = a.split(',').each
e2 = b.each
loop do
y << e1.next.strip << e1.next.strip << e2.next
end
end
puts enum.to_a.join(', ')
#=> 1, 2, 9, 3, 4, 10, 5, 6, 11, 7, 8, 12
You could also use this if you are sure that every number is separated by a comma and a space :
enum = Enumerator.new do |y|
e1 = a.split(', ').each
e2 = b.each
loop do
y << e1.next << e1.next << e2.next
end
end

Related

How to remove array elements and append it to the front of the array in ruby without using any inbuilt methods?

I have an array say [1,2,3,4,5,6,7,8]. I need to take an input from the user and remove the last input number of array elements and append it to the front of the array. This is what I have achieved
def test(number, array)
b = array - array[0...(array.length-1) - number]
array = array.unshift(b).flatten.uniq
return array
end
number = gets.chomp_to_i
array = [1,2,3,4,5,7,8,9]
now passing the argument to test gives me the result. However, there are two problems here. first is I want to find a way to do this append on the front without any inbuilt method.(i.e not using unshift).Second, I am using Uniq here, which is wrong since the original array values may repeat. So how do I still ensure to get the correct output? Can some one give me a better solution to this.
The standard way is:
[1, 2, 3, 4, 5, 7, 8, 9].rotate(-3) #=> [7, 8, 9, 1, 2, 3, 4, 5]
Based on the link I supplied in the comments, I threw this together using the answer to that question.
def test(number, array)
reverse_array(array, 0, array.length - 1)
reverse_array(array, 0, number - 1)
reverse_array(array, number, array.length - 1)
array
end
def reverse_array(array, low, high)
while low < high
array[low], array[high] = array[high], array[low]
low += 1
high -= 1
end
end
and then the tests
array = [1,2,3,4,5,7,8,9]
test(2, array)
#=> [8, 9, 1, 2, 3, 4, 5, 7]
array = [3, 4, 5, 2, 3, 1, 4]
test(2, array)
#=> [1, 4, 3, 4, 5, 2, 3]
Which I believe is what you're wanting, and I feel sufficiently avoids ruby built-ins (no matter what way you look at it, you're going to need to get the value at an index and set a value at an index to do this in place)
I want to find a way to do this append on the front without any inbuilt method
You can decompose an array during assignment:
array = [1, 2, 3, 4, 5, 6, 7, 8]
*remaining, last = array
remaining #=> [1, 2, 3, 4, 5, 6, 7]
last #=> 8
The splat operator (*) gathers any remaining elements. The last element will be assigned to last, the remaining elements (all but the last element) are assigned to remaining (as a new array).
Likewise, you can implicitly create an array during assignment:
array = last, *remaining
#=> [8, 1, 2, 3, 4, 5, 6, 7]
Here, the splat operator unpacks the array, so you don't get [8, [1, 2, 3, 4, 5, 6, 7]]
The above moves the last element to the front. To rotate an array n times this way, use a loop:
array = [1, 2, 3, 4, 5, 6, 7, 8]
n = 3
n.times do
*remaining, last = array
array = last, *remaining
end
array
#=> [6, 7, 8, 1, 2, 3, 4, 5]
Aside from times, no methods were called explicitly.
You could create a new Array with the elements at the correct position thanks to modulo:
array = %w[a b c d e f g h i]
shift = 3
n = array.size
p Array.new(n) { |i| array[(i - shift) % n] }
# ["g", "h", "i", "a", "b", "c", "d", "e", "f"]
Array.new() is a builtin method though ;)

Remove redundant or duplicate tuples in Ruby array

Imagine the following Ruby array:
[9, 9, 5, 5, 5, 2, 9, 9]
What's the easiest way of removing redundant tuples, producing an output like the following:
[9, 5, 2, 9]
uniq is not correct because it's examining the entire array. The ordering of the input is important and must be kept. Is there a straightforward approach to this?
Thanks!
I'd do using Enumerable#chunk
2.0.0-p0 :001 > a = [9, 9, 5, 5, 5, 2, 9, 9]
=> [9, 9, 5, 5, 5, 2, 9, 9]
2.0.0-p0 :002 > a.chunk { |e| e }.map(&:first)
=> [9, 5, 2, 9]
I would do it like
b = [];
a.each { |n| b << n if b.last != n }
and b is the result
only one array scan is needed
I like Arup's answer best, but in case you want a method that is compatible with versions that don't have chunk you can do
a = [9, 9, 5, 5, 5, 2, 9, 9]
a.inject([a[0]]) { |b,c| b.last == c ? b : b << c }
# => [9, 5, 2, 9]
This is my version:
a.each_with_object([]) { |el, arr| arr << el if arr.last != el }
#=> [9, 5, 2, 9]
For those who land on this question looking to remove "redundant" values, the OP is trying to remove "repeated consecutive" values, not "redundant" or "duplicate" values and used the wrong word. They are different situations.
For clarification, removing redundant or duplicate values would be:
asdf = [9, 9, 5, 5, 5, 2, 9, 9]
asdf.uniq # => [9, 5, 2]
Or:
asdf & asdf # => [9, 5, 2]
Or:
require 'set'
asdf.to_set.to_a # => [9, 5, 2]
And, yes, I know the OP is asking for a different result. This is to show the answer for the question that was asked, NOT what what would meet the desired output. For that see the selected answer.
This is to show how you could use an enumerator directly, with the methods Enumerator#next and Enumerator#peek.
def purge_conseq_dups(arr)
return arr if arr.empty?
enum = arr.to_enum
a = []
loop do
e = enum.next
a << e unless e == enum.peek
end
a << arr.last
end
asdf = [9, 9, 5, 5, 5, 2, 9, 9]
purge_conseq_dups(asdf) #=> [9, 5, 2, 9]
When e is the last element of the enumerator enum, enum.peek raises a StopInteration exception which is rescued by Kernel#loop, which responds by breaking out of the loop. At that point all that remains is to append the last element of arr to a.
We could write a << e rather than a << arr.last, provided we initialize e prior to the loop (e.g., e = nil) so that the variable will be in scope in the last line.

Dividing elements of a ruby array into an exact number of (nearly) equal-sized sub-arrays [duplicate]

This question already has answers here:
How to chunk an array in Ruby
(2 answers)
Closed 4 years ago.
I need a way to split an array in to an exact number of smaller arrays of roughly-equal size. Anyone have any method of doing this?
For instance
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
groups = a.method_i_need(3)
groups.inspect
=> [[1,2,3,4,5], [6,7,8,9], [10,11,12,13]]
Note that this is an entirely separate problem from dividing an array into chunks, because a.each_slice(3).to_a would produce 5 groups (not 3, like we desire) and the final group may be a completely different size than the others:
[[1,2,3], [4,5,6], [7,8,9], [10,11,12], [13]] # this is NOT desired here.
In this problem, the desired number of chunks is specified in advance, and the sizes of each chunk will differ by 1 at most.
You're looking for Enumerable#each_slice
a = [0, 1, 2, 3, 4, 5, 6, 7]
a.each_slice(3) # => #<Enumerator: [0, 1, 2, 3, 4, 5, 6, 7]:each_slice(3)>
a.each_slice(3).to_a # => [[0, 1, 2], [3, 4, 5], [6, 7]]
Perhaps I'm misreading the question since the other answer is already accepted, but it sounded like you wanted to split the array in to 3 equal groups, regardless of the size of each group, rather than split it into N groups of 3 as the previous answers do. If that's what you're looking for, Rails (ActiveSupport) also has a method called in_groups:
a = [0,1,2,3,4,5,6]
a.in_groups(2) # => [[0,1,2,3],[4,5,6,nil]]
a.in_groups(3, false) # => [[0,1,2],[3,4], [5,6]]
I don't think there is a ruby equivalent, however, you can get roughly the same results by adding this simple method:
class Array; def in_groups(num_groups)
return [] if num_groups == 0
slice_size = (self.size/Float(num_groups)).ceil
groups = self.each_slice(slice_size).to_a
end; end
a.in_groups(3) # => [[0,1,2], [3,4,5], [6]]
The only difference (as you can see) is that this won't spread the "empty space" across all the groups; every group but the last is equal in size, and the last group always holds the remainder plus all the "empty space".
Update:
As #rimsky astutely pointed out, the above method will not always result in the correct number of groups (sometimes it will create multiple "empty groups" at the end, and leave them out). Here's an updated version, pared down from ActiveSupport's definition which spreads the extras out to fill the requested number of groups.
def in_groups(number)
group_size = size / number
leftovers = size % number
groups = []
start = 0
number.times do |index|
length = group_size + (leftovers > 0 && leftovers > index ? 1 : 0)
groups << slice(start, length)
start += length
end
groups
end
Try
a.in_groups_of(3,false)
It will do your job
As mltsy wrote, in_groups(n, false) should do the job.
I just wanted to add a small trick to get the right balance
my_array.in_group(my_array.size.quo(max_size).ceil, false).
Here is an example to illustrate that trick:
a = (0..8).to_a
a.in_groups(4, false) => [[0, 1, 2], [3, 4], [5, 6], [7, 8]]
a.in_groups(a.size.quo(4).ceil, false) => [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
This needs some better cleverness to smear out the extra pieces, but it's a reasonable start.
def i_need(bits, r)
c = r.count
(1..bits - 1).map { |i| r.shift((c + i) * 1.0 / bits ) } + [r]
end
> i_need(2, [1, 3, 5, 7, 2, 4, 6, 8])
=> [[1, 3, 5, 7], [2, 4, 6, 8]]
> i_need(3, [1, 3, 5, 7, 2, 4, 6, 8])
=> [[1, 3, 5], [7, 2, 4], [6, 8]]
> i_need(5, [1, 3, 5, 7, 2, 4, 6, 8])
=> [[1, 3], [5, 7], [2, 4], [6], [8]]

A more balanced array manipulation than each_slice?

I have an array of 10 items and I want to split it up into 3 sections that look like this:
[1, 2, 3, 4]
[5, 6, 7]
[8, 9, 10]
Using each_slice I can get close:
a = *(1..10)
a.each_slice(4) # use 4 so I can fit everything into 3 sections
[1, 2, 3, 4]
[5, 6, 7, 8]
[9, 10]
But I want the first format which is more evenly distributed. I can do it writing my own method. But is there a built in way to do this in ruby 1.9+?
Update:
Since there's no built in way I'd like to change my question to - how would you implement it?
Here's my implementation
def chunk(a, pieces)
size = a.size / pieces
extra = a.size % pieces
chunks = []
start = 0
1.upto(pieces) do |i|
last = (i <= extra) ? size.next : size
chunks << a.slice(start, last)
start = chunks.flatten.size
end
chunks
end
call it like so
a = *(1..10)
puts chunk(a, 3)
will output
[1, 2, 3, 4]
[5, 6, 7]
[8, 9, 10]
If piece size is too big it pads with empty arrays
a = *(1..10)
puts chunk(a, 14)
will output
[[1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [], [], [], []]

How to Line Chart this data?

I would like to create line chart for following data. I would also like to have the ability to hover over each data point to look at the x and y value at that data point. I have the following data structure:
x[0] = [23 4 2 2 4 4 5 3 334 2]
y[0] = [6 24 1 2 2 5 1 3 8 0]
x[1] = [5 6 8 6 3 4 6 3 3]
y[1] = [9 7 8 6 3 4 1 9 2]
x[2] = [6 9 9 6 2 5 8 3]
y[2] = [1 0 2 5 6 2 1 5]
... so that I will have 3 lines on the same chart.
I played with "Seer" without much success. Can anyone provide any recommendations / examples / references for plotting similar data using Seer or anything else?
Thanks.
Give the lazy_high_charts gem a try.
#app/views/layouts/appliction.*
= javascript_include_tag 'highcharts.js'
#Gemfile
gem 'lazy_high_charts'
# my_controller#my_action
x_0 = [23, 4, 2, 2, 4, 4, 5, 3, 334, 2]
y_0= [6, 24, 1, 2, 2, 5, 1, 3, 8, 0]
x_1 = [5, 6, 8, 6, 3, 4, 6, 3, 3]
y_1 = [9, 7, 8, 6, 3, 4, 1, 9, 2]
x_2 = [6, 9, 9, 6, 2, 5, 8, 3]
y_2 = [1, 0, 2, 5, 6, 2, 1, 5]
data_0 = x_0.zip(y_0)
data_1 = x_1.zip(y_1)
data_2 = x_2.zip(y_2)
#h = LazyHighCharts::HighChart.new('graph') do |f|
f.series(:name => "xy0", :data => data_0)
f.series(:name => "xy1", :data => data_1)
f.series(:name => "xy3", :data => data_2)
f.chart({:defaultSeriesType=>"line" })
f.yAxis(:title => { :text => "y axis values" } )
f.xAxis(:title => { :text => "x axis values"} )
f.title(:text => "XY Graph")
f.plotOptions({}) # override the default values that lazy_high_charts puts there
f.legend({}) # override the default values
end
#app/views/my_controller/my_action
= high_chart("chart", #h)
Caveat:
HighCharts is only free for non-commercial use. That may or may not be a dealbreaker for you.
I've really liked jQuery flot for this kind of thing:
http://code.google.com/p/flot/
Check out the example here:
http://flot.googlecode.com/svn/trunk/README.txt
In your controller or view, you can use Ruby's zip to zip together arrays of x and y values if you need to:
> a = [1,2,3]
=> [1, 2, 3]
> b = [5,6,7]
=> [5, 6, 7]
> a.zip(b)
=> [[1, 5], [2, 6], [3, 7]]

Resources