Ruby - count identical elements in array, add up, and print [duplicate] - ruby

This question already has answers here:
duplicates in 2 dimensional array
(2 answers)
Closed 9 years ago.
I have this input .txt file loaded into array so it comes out like this:
class Note
def initialize(a, b)
#a = a
#b = b
end
end
input = File.open("DATA", "r")
input.each do |line|
l = line.split(',')
arr << Note.new(l[0], l[1])
end
I want to count and output to another .txt file how many times each inner array is equal to another inner array, e.g. [500, 2, x], where x is the times the [500, 2] array is represented in arr.
input.txt example
10000, 150
00500, 10
08000, 171
00045, 92
00045, 93
00045, 92
00045, 93
expected output
10000, 150, 1
00500, 10, 1
08000, 171, 1
00045, 92, 2
00045, 93, 2
Thanks in advance.

What about this:
arr.uniq.map {|el| [*el, arr.count(el)] }
For each unique element of the array, count how may times it is there and make a new array with the element and its count.
Example:
arr = [[1,2], [5,5], [5,5], [8,7], [1,2], [5,5]]
#=> [[1, 2, 2], [5, 5, 3], [8, 7, 1]]

Is this what you are looking for :
arr = [[5000, 52],[99422, 1],[5000, 52],[325, 63]]
arr.group_by{|a| a }.map{|k,v| [*k,v.size]}
# => [[5000, 52, 2], [99422, 1, 1], [325, 63, 1]]
Edit
ar = File.readlines("/home/kirti/Ruby/input.txt").map{|s| s.scan(/\w+/) }
ar.group_by{|a| a }.map{|k,v| [*k,v.size]}
# => [["10000", "150", 1],
# ["00500", "10", 1],
# ["08000", "171", 1],
# ["00045", "92", 2],
# ["00045", "93", 2]]

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

Ruby program to create even_odd method that accepts the whole number

I need help to write even_odd method that accepts an array of whole number.
It should return an array of 2 arrays
The first nested array should contain only the odd numbers
The second nested array should contain only the even numbers
If there are no even or odd numbers, the respective inner array should be empty
Output should look like this : -
even_odd([3, 5, 8, 2, 4, 6])
[[3, 5], [2, 4, 6, 8]]
even_odd([3, 5])
[[3, 5], []]
even_odd([2, 4])
[[], [2, 4]]
I am new to ruby programming, I have tried below but not getting the result :-
def even_odd(numbers)
arr1, arr2 = []
idx = 0
while idx < numbers.length
if numbers[idx] % 2 == 0
puts arr1[idx]
elsif
puts arr2[idx]
end
idx += 1
end
end
puts even_odd([2, 3, 6])
Error :-
main.rb:6:in `even_odd': undefined method `[]' for nil:NilClass (NoMethodError)
from main.rb:13:in `<main>'
I would do this
def even_odd(numbers)
numbers.sort.partition(&:odd?)
end
even_odd([3, 5, 8, 2, 4, 6])
# => [[3, 5], [2, 4, 6, 8]]
even_odd([3, 5])
# => [[3, 5], []]
even_odd([2, 4])
# => [[], [2, 4]]
puts is a print statement in ruby, not an append one. It also doesn't run a function/method. You'll also want to call the index on the numbers array inside the if...else block.
This should do the trick:
def even_odd(numbers)
arr1, arr2 = [], []
idx = 0
while idx < numbers.length
if numbers[idx] % 2 == 0
arr1 << numbers[idx]
elsif
arr2 << numbers[idx]
end
idx += 1
end
return arr1, arr2
end
arrays = even_odd([2, 3, 6])
puts arrays

If I have an array of arrays, how do I separate the arrays?

I have an array that consists of other arrays, for example [[1, 52], [30, 1], [2, 1]]. I would like to use each individual array separately. Using a loop just breaks it down to all the numbers individually.
arrays = [[1, 52], [30, 1], [2, 1]]
irb(main):003:0* arrays.each do |array|
irb(main):004:1* puts array
irb(main):005:1> end
1
52
30
1
2
1
=> [[1, 52], [30, 1], [2, 1]]
I'd like to loop through the arrays. What function can I use for this?
I'd like puts array to display this instead;
[1, 52]
[30, 1]
[2, 1]
You are looping through the arrays. The puts function on its own just makes that difficult to see. Try this:
arrays = [[1, 52], [30, 1], [2, 1]]
arrays.each do |array|
puts array.inspect
end
Output:
[1, 52]
[30, 1]
[2, 1]
See also:
puts [1, 2, 3]
Output:
1
2
3
p array
.................................
You are looping through the arrays, it's just that puts() doesn't output an array so that it looks like an array. When you give puts() an array as an argument, it outputs each element separated by newlines.
Examine the output here:
arrays = [[1, 52], [30, 1], [2, 1]]
arrays.each do |x|
puts x.class
puts x.size
puts x[-1]
end
--output:--
Array
2
52
Array
2
1
Array
2
1
The output shows that each() assigns each inner array to the loop variable x. Likewise,
Array methods, like size() and [] work on x.

How to group a data by week and show a 0 when there is no data

I have a set of numbers attached to dates. What I need to do is take those numbers and group them by calendar week. Generally speaking, that works fine...except for when there's a week when there are no numbers.
Here's the hash of numbers:
chart_numbers = {"2014-02-20"=>1, "2014-02-23"=>4, "2014-02-24"=>1, "2014-03-06"=>1, "2014-03-14"=>3, "2014-03-15"=>1, "2014-03-17"=>1, "2014-03-20"=>1, "2014-03-21"=>1, "2014-03-24"=>1, "2014-03-25"=>1, "2014-03-28"=>1, "2014-04-05"=>1, "2014-04-07"=>1}
Here are the "week" timestamps (these are use for the javascript charting library). As you can see, there are 9 timestamps.
chart_weekly_timestamps = [1392595199, 1393199999, 1393804799, 1394409599, 1395014399, 1395619199, 1396223999, 1396828799, 1397433599]
Finally, here's the code that takes the chart_numbers and sums them up in to calendar weeks.
chart_week = Hash[ chart_numbers.map { |h, v| [h, v] } ].group_by { |h, v| Date.parse(h).cweek }.values.map{ |v| v.sum { |vv| vv.last } }.map{ |v| v.round(0) } %>
The output from that is: [5, 1, 1, 4, 3, 3, 1, 1]
And there's where the problem lies. There are only 8 items in that array. But I need to match it up to the week timestamps above, which have 9 array items.
So what I need to do is when there's a week with no data, I need to show a 0 as an array item.
Here is one way to construct the array you want.
Code
require 'date'
a = chart_numbers.map { |d,n| [Date.parse(d).cweek, n] }
h = (a.min_by(&:first).first..(a.max_by(&:first).first)).each_with_object({}) \
{ |(w,_),h| h[w] = 0 }
a.each { |w,n| h[w] += n }
h.values
For Ruby versions prior to 1.9, add .sort to the end of the last line.
Explanation
I modified the last date in chart_numbers to produce an unrepresented week
and also moved the date at offset 7 to offset 1 so they would not be ordered.
chart_numbers =
{"2014-02-20"=>1, "2014-03-20"=>1, "2014-02-23"=>4, "2014-02-24"=>1,
"2014-03-06"=>1, "2014-03-14"=>3, "2014-03-15"=>1, "2014-03-17"=>1,
"2014-03-21"=>1, "2014-03-24"=>1, "2014-03-25"=>1, "2014-03-28"=>1,
"2014-04-05"=>1, "2014-04-17"=>1}
Convert the dates to weeks and chart_numbers to an array.
a = chart_numbers.map { |d,n| [Date.parse(d).cweek, n] }
#=> [[8 , 1], [12, 1], [8 , 4], [9 , 1], [10, 1], [11, 3], [11, 1],
# [12, 1], [12, 1], [13, 1], [13, 1], [13, 1], [14, 1], [16, 1]]
Note there is no week 15. Now create a hash with keys from 8 through 16, with all values zero.
h = (a.min_by(&:first).first..(a.max_by(&:first).first)).each_with_object({}) \
{ |(w,_),h| h[w] = 0 }
#=> {8=>0, 9=>0, 10=>0, 11=>0, 12=>0, 13=>0, 14=>0, 15=>0, 16=>0}
Add up the values from the original hash:
a.each { |w,n| h[w] += n }
so now
h #=> {8=>5, 9=>1, 10=>1, 11=>4, 12=>3, 13=>3, 14=>1, 15=>0, 16=>1}
Retrieve the hash values:
h.values
#=> [5, 1, 1, 4, 3, 3, 1, 0, 1]
I recently published a gem OrderedWeek that handles groups of days as a single unit. Take a gander. I'd love some feedback on it as well.

Iterate array and leave one out in each step

How do I iterate the elements of an array in Ruby and in each step I can do something with the array containing all elements, except the one that is iterated in the moment?
For instance for [4,2,8] I iterate the elements and then I can do something with
[2,8]
[4,8]
[4,2]
It's not really directly possible (unless you do not need the missing element). But you can program it yourself:
Option 1 - just do it:
a = [11,22,33,44,55]
a.each_with_index { |e,i|
p e
p a.take(i) + a[i+1..-1]
}
Option 2 - integrate with Array:
class Array
def each_excluded(&block)
self.each_with_index { |e, i|
yield(e, self.take(i) + self[i+1..-1])
}
end
end
a.each_excluded { |e, rest|
p e
p rest
}
Output from either one:
11
[22, 33, 44, 55]
22
[11, 33, 44, 55]
33
[11, 22, 44, 55]
44
[11, 22, 33, 55]
55
[11, 22, 33, 44]
You can use the slice method and create a new array with the items except for the one in which have the index for.
[4, 2, 8].tap{|a| a.length.times{|i|
do_something_you_want_with(a[0...i]+a[i+1..-1])
}}
or
class Array
def each_but_one &pr
length.times{|i| pr.call(self[0...i]+self[i+1..-1])}
end
end
[4, 2, 8].each_but_one{|a| do_something_you_want_with(a)}
It really looks like you want Array#combination:
[4,2,8].combination(2).each do |ary|
p ary
end
Which outputs:
[4, 2]
[4, 8]
[2, 8]
Each sub-array created is yielded to the block, in this case to ary, so you can do what you want with the values.

Resources