How to find all the ranges in an array of numbers - arrays

I have an array of numbers that sorted. I need a method that return ranges of numbers in this array.
input: [1,2,3,7,9,10,11,13]
output: [(1..3),(7..7),(9..11),(13..13)]

You didn't write any code, so I won't either.
The documentation of Enumerable#chunk_while has an example which is very similar to yours.

This is a way of doing that without constructing an array of arrays and then converting the inner arrays to ranges.
arr = [1,2,3,7,9,10,11,13]
arr.each_with_object([]) do |n,a|
if a.any? and a.last.last == n-1
a[-1] = (a.last.first..n)
else
a << (n..n)
end
end
#=> [1..3, 7..7, 9..11, 13..13]
Note that parentheses are required around the ranges, lest, for example, a << n..n be parsed as (a << n)..n, resulting in ArgumentError (bad value for range).

Related

Count the number of elements of array that contain a digit

i am new to Ruby and stuck on this exercice. I have this array including string value and i am looking for the number of value including a figure ?
array = ["#jcunniet","#PaulLampon","#Aziliz31","#ssoumier","#marionsouzeau","#gaellombart","#bendarag","#AurelieLebelle","#julienduffe","#thomaspoupeau","#LilyRossignol","#ClairGuedon","#stephanieauguy","#claw_prolongeau","#_JulieMenard","#LColcomb","#Zlauwereys","#MeLonguet","#DorotheeLN","#NolwennCosson","#ADaboval","#Remibaldy","#bderveaux","#amandechap","#ELODIESOULIE","#nbongarcon","#HeloAb","#Panamorama","#gregplou","#BenoitBerthe","#LauraBruneau89","#Anthony_Lieures","#Sharonwaj","#mcsonkin","#pverduzier","#emiliel3","#Julien_MARION","#SophiFay","#bdelombre","#annalecerf","#AdriaBudry","#DejNikolic","#iJaffre","#CyrusleVirus","#GPardigon","#e_vallerey","#IsabelleSouquet","#AudeDavidRossi","#Yoann_Pa","#CeliaPenavaire","#perraultvincent","#cboulate","#JustineWeyl","#Paulinejacot","#juliechab","#aslechevallier","#phnou","#Seb_Pommier","#Alex_Bensaid","#GuillaumeGaven","#annelaurechouin","#Oliviader","#guerricp","#JMMarchaut","#cyceron","#gregory_raymond","#vhunsinger","#l_peillon","#fannyguinochet","#EAssayag","#KibweAdom","#YvonHerry","#JohanGarciajg","#saidlabidi","#lauranneprov","#LeaDavy","#francois_remy","#CGuicheteau","#FloMaillet","#m_perroud","#oBrunet_TSMF","#MoonVdc","#jc2taille","#NellyMoussu","#VirginK","#b_misa","#FabriceCouste","#barbara_prose","#lelia2m","#brunoaskenazi","#laurenechamp","#ysisbox","#juliengagliardi","#PierreLel","#kdeniau","#_TerraInc","#DominicArpin","#antoinfonteneau","#nanotousch","#jb_roch","#YaniKhezzar","#Anne_Bechet","#NCapart","#SamyBenNaceur","#Joumany","#Julietteraynal","#TGiraudet","#SaraTanit","#HappeFrederic","#antoinellorca","#michelpicot","#Sev_Ryne","#bobdobolino","#murdever","#YGrandmontagne","#Mnyo","#EdKOSCIANSKI","#tnoisette","#jankari","#delbello_rom","#rflechaux","#NadiaSorelli","#IT_Digital","#abarbaux","#PhilippeLeroy","#schaptal","#marionspee","#lisavignoli","#ChloeAeberhardt","#MartineJacot","#JuliaPascualita","#curieusedetout","#sgraveleau","#bif_o","#ElisaPineau","#zinebdryef","#apiquard","#pierrehaski","#StephanieDelmas","#Blandine_Garot","#vergara_i","#evan_lebastard","#SophieVclt","#OlivierLevrault","#alicedorgeval","#LouiseMalnoy","#alix_fx","#pierre_baudis","#LucMagoutier","#AgatheMuller","#SGianninelli","#PaulineBoyer33","#NaomiHalll","#romaindlx","#marionbr","#Burtschy","#JacobEtienne","#as_lizzani","#marie_simon","#LaureDaussy","#FabriceAmedeo","#LoubnaChlaikhy","#PlummerWilliam","#OlivierMarin1","#alaurefremont","#mwesfreid","#ChBaDe","#pmathon","#theobaldmarie","#Lnpagesy","#marclandre","#paoliniesther","#Feertchak","#JBLitzler","#GuillaumeErrard","#quentinperinel","#TristanQM","#mlbo","#constancejamet","#LoraTerrazas","#emiliegeffray","#Mathilde_Sd","#CaroPiquet","#DCanivez","#TIM_7375","#blandinelc","#ivanrioufol","#arthurberdah","#SarahLecoeuvre","#guillaume_gui","#DamienMercereau","#W_Chloe","#Assma_MD","#EugenieBastie","#HiTech_lexpress","#bcondominas","#Laurie_Z_","#jeanfrancgerard","#MathieuPagura","#BGUYF","#AlainPiffaretti","#AudreyKucinskas","#julienhory","#Pierrefalga","#TiphThuillier","#cdaniez","#LigerBaptiste","#D_Peras","#julie_dlb","#Fatiha_Temmouri","#julian2lamancha","#GaetaneDeljurie","#JulianMattei","#M_Vicuna","#DeBruynOlivier","#Nehed_Jendoubi","#antoine_grenapi","#ColonnaGen","#VictoriaGairin","#Clement_Lacombe","#TVigoureux","#MargauxObriot","#solinedelos","#RocheSabine","#dangerkens","#EdouardDutour","#MDondeyne","#DupuisNathalie1","#bouscarel","#Mathieu2jean","#Sophie_T_J","#laurentcalixte","#patrockwilliams","#PascaleKremer","#AlexJaquin","#LauraIsaaz","#cath_robin","#Del_Gautherin","#Isaduriez","#lucietuile","#AugeyBastien","#mcastagnet","#AminaKalache","#mvaudano","#CParrot","#ombelinetips","#_JoinLion","#BarbolosiRose","#ToiBruno1","#FloraClodic","#xjbdx","#AlexiaEy","#Emjy_STARK","#elcoco01","#rabilebon","#pflovens_","#FabriceFrossard","#MorganeSERRES","#MarjolaineKoch","#edgarsnow","#SRNLF","#CChassigneux","#KerinecMoran","#NassiraELM","#NewsRicard","#Sandreene","#Emilezrt","#Pierre_Do","#Micode","#CColumelli","#DavidAbiker","#ClementBergantz","#benjaminrabier","#celinekallmann","#edwyplenel","#C_Barbier","#JJBourdin_RMC","#LaurenceFerrari","#aslapix","#IsaMillet","#MaximeSwitek","#tomjoubert","#jszanchi","#roqueeva","#XavierBiseul","#florencesantrot","#AntoineCrochet","#freeman59","#MaudeML","#philippe_gulpi","#mathieum76","#kiouari","#imanemoustakir","#BenedicteMallet","#Emilie_Brouze","#antoinebarret","#_nicolasbocquet","#remibuhagiar","#CourretB","#AymericRobert","#miraelmartins","#pmaniere","#jesuisraphk","#David_Ingram","#pcelerier","#technomedia","#Geraldinedauver","#ThierryLabro","#Newsdusud","#nrauline","#gbregeras","#SCouasnonBFM","#actualites_nrv","#dimitrimoulins","#oli_aura","#FabieChiche","#Vincent_Raimblt","#ChristophGreuet","#PAlbuchay","#MarrauddesGrot","#vtalmon","#cedric","#olivierfrigara","#Julien_Jay","#LydiaBerroyer","#Shuua","#datisdaz","#Steuph","#ameliecharnay","#Bruno_LesNums","#LelloucheNico","#CciliaDiQuinzio","#Elodie_C","#SylvRolland","#Kocobe","#FL_Debes","#jdupontcalbo","#GarciaVictor_","#NicoRichaud","#RHoueix","#simottel","#DamienLicata","#annabelle_L","#Lea_Lejeune","#axel_deb","#marin_eben","#ptiberry","#MatthieuDelach","#sandrinecassini","#benjaminferran","#ppgarcia75","#NotPatrick","#ivalerio","#FabienneSchmitt","#alexgoude","#JeromeColombain","#manhack","#Capucine_Cousin","#Fsorel","#oliviertesquet","#marjoriepaillon","#ginades","#PierreTran","#DelphineCuny","#reesmarc","#lauratenoudji","#ldupin","#carolinedescham","#Lucile_Quillet","#cgabizon","#Allocab","#epenser","#JAGventeprivee","#frwrds","#Laure__Bourdon","#Xavier75","#maximeverner","#s_jourdain","#LoriHelloc"]
i = 0
array.each do |n|
if n.include?("1,2,3,4,5,6,7,8,9,10")
then i += 1
end
puts i
end
Do you mean something like this?
array.grep(/[1-9]/).count
Edit: Changed regEx from /[1-10]/ to /[1-9]/
Often code that is the direct translation of the question is best: “Count the number of elements of array that contain a digit”.
array.count { |s| s.match? /\d/ }
See Array#count and String#match?.

How can I duplicate and delete from an array without changing the original one?

My goal is to write a method, trickysum(n) that does the following:
The method takes range of numbers 1 through n. The method then finds pairs of numbers in that range that meet a tricky qualification: The product of the pair of numbers must be equal to the sum of all numbers in the range, excluding this pair. The method then returns all number pairs that meet this qualification. Here is the expectation:
trickysum(26)
#=>[(15, 21), (21, 15)]
Here is the code I have so far:
def trickysum(n)
result = []
arr = (1..n).to_a
0.upto(arr.length - 1) do |x|
0.upto(arr.length - 1) do |y|
prod = arr[x] * arr[y]
#I create a new array to delete from to not affect the original
#array. Would also love an easier way to do this :)
new_arr = arr
new_arr.delete(new_arr[x])
new_arr.delete(new_arr[y])
sum = new_arr.inject(:+)
if sum == prod
result << "(#{arr[x]},#{arr[y]})"
end
end
end
result
end
I've looked over this code over and over and can't figure out why I'm getting the following error:
nil can't be coerced into Fixnum
(repl):7:in `*'
(repl):7:in `block (2 levels) in trickysum'
(repl):6:in `upto'
(repl):6:in `block in trickysum'
(repl):5:in `upto'
(repl):5:in `trickysum'
(repl):20:in `<main>'
Where am I going wrong?
Replace:
new_arr = arr
With:
new_arr = arr.dup
What's happening here is that you have created a shallow copy of the arr variable. Without explicitly duplicating the value, both new_arr and arr share the same location in memory.
Because of this, when you call new_arr.delete(new_arr[x]) and new_arr.delete(new_arr[y]), not only are you mutating the new array, but also the old one.
This means arr gets shorter in length, so your outer loop goes beyond its final value and you get a nil; hence the error.
With that said, I would have written this method totally differently, which would have avoided such subtle errors:
def trickysum(n)
sum = (1..n).inject(:+)
(1..n).combination(2).select do |a, b|
(a * b) + a + b == sum
end
end
Ruby is a very expressive language. If you find yourself doing looping within loops, declaring temporary variables and appending to an array of results ... Then there's probably a much more elegant solution :)

Strange output in Ruby Longest Palindrome substring function

I am trying to develop a function which will return the longest palindrome substring of an entered string. I am right now working on breaking up the string so that each subsection could then be analyzed to see if it is a palindromeThe code is as follows:
def longest_palindrome(s)
place = 0
array = s.chars
output = []
while place < s.length
output << (array[0]..array[place]).to_a
place += 1
end
return output
end
if given string "ababa" I would expect the resulting array to look like this:
[["a"],["a","b"],["a","b","a"],["a","b","a","b"],["a","b","a","b","a"]]
However, when i return the output array this is what is stored inside:
[["a"], ["a", "b"], ["a"], ["a", "b"], ["a"], ["a", "b"]]
What about my function is causing this to happen?
Edit:
Not sure if I should start another topic for this. My code is now as follows:
def longest_palindrome(s)
array = s.chars
start = 0
place = 1
output = []
while start < s.length - 1
while place < s.length
output << array[start..place]
place += 1
end
start += 1
end
return output
end
My logic is that this will start at index 0, then progressively capture one character more of the string until the whole string is complete. Then it will start on index 1 and do the same until it has gotten all possible substrings within the string. However, it only returns:
[["a"],["a","b"],["a","b","a"],["a","b","a","b"],["a","b","a","b","a"]]
Where is the flaw in my logic?
You're misusing the range operator to produce ranges like 'a'..'a', which is just 'a'.
You have two completely independent array indexing operations, each of which return a single element (character) from the array to be used in a range. You're getting array[0], which is always a, and array[place] which alternates between a and b, and producing the ranges 'a'..'a' and 'a'..'b' over and over, which have nothing to do with the arrays the characters originally came from.
You can't build the ranges after extracting the elements from the array and expect the ranges to be produced from the array. The correct sub-array is produced by using the range as the index of the array: array[0..place]. This returns the sub-array from 0 to place, inclusive.

Find a Duplicate in an array Ruby

I am trying to find the duplicate values in an array of strings between 1 to 1000000.
However, with the code I have, I get the output as all the entries that are doubled.
So for instance, if I have [1,2,3,4,3,4], it gives me the output of 3 4 3 4 instead of 3 4.
Here is my code:
array = [gets]
if array.uniq.length == array.length
puts "array does not contain duplicates"
else
puts "array does contain duplicates"
print array.select{ |x| array.count(x) > 1}
end
Also, every time I test my code, I have to define the array as array = [1,2,3,4,5,3,5]. The puts works but it does not print when I use array [gets].
Can someone help me how to fix these two problems?
How I wish we had a built-in method Array#difference:
class Array
def difference(other)
h = other.tally
reject { |e| h[e] > 0 && h[e] -= 1 }
end
end
though #user123's answer is more straightforward. (Array#difference is probably the more efficient of the two, as it avoids the repeated invocations of count.) See my answer here for a description of the method and links to its use.
In a nutshell, it differs from Array#- as illustrated in the following example:
a = [1,2,3,4,3,2,4,2]
b = [2,3,4,4,4]
a - b #=> [1]
a.difference b #=> [1, 3, 2, 2]
For the present problem, if:
arr = [1,2,3,4,3,4]
the duplicate elements are given by:
arr.difference(arr.uniq).uniq
#=> [3, 4]
For your first problem, you need to uniq function like
array.select{ |x| array.count(x) > 1}.uniq
For your second problem, when you receive a value using array = [gets] it would receive your entire sequence of array numbers as a single string, so everything would be stored in a[0] like ["1, 2 3 4\n"].
puts "Enter array"
array = gets.chomp.split(",").map(&:to_i)
if array.uniq.length == array.length
puts "array does not contain duplicates"
else
puts "array does contain duplicates"
print array.select{ |x| array.count(x) > 1}.uniq
end
copy this code in ruby file and try to run using
ruby file_name.rb
Coming to your 'gets' problem,
When you are doing a gets, your are basically getting a string as an input but not an array.
2.2.0 :001 > array = [gets]
1,2,1,4,1,2,3
=> ["1,2,1,4,1,2,3\n"]
See the above example, how the ruby interpreter took all your elements as a single string and put it in an array as a single array element. So you need to explicitly convert the input to an array with comma as a delimiter. The below will address both your questions.
array = gets.chomp
array = array.split(',').map(&:to_i)
if array.uniq.length == array.length
puts "array does not contain duplicates"
else
puts "array does contain duplicates"
print array.select{ |x| array.count(x) > 1}.uniq!
end

Methods of List comprehension, join a list with a different string at set intervals. (language agnostic)

I'm interested in possible ways that different languages can Join an array, but rather than using a single join string, using a different join string at given intervals.
For example (hypothetical language):
Array.modJoin([mod, char], ...)
e.g. [1,2,3,4,5].modJoin( [1, ","], [2, ":"] )
Where the arguments specify an array or object containing a modulo and a join char, the implementation would check which order of modulo took precedence (the latest one), and apply the join char. (requiring that the [mod,char]'s were provided in ascending mod order)
i.e.
if (index % (nth mod) == 0)
append (join char)
continue to next index
else
(nth mod)-- repeat
when complete join with ""
For example, I've come up with the following in Ruby, but I suspect better / more elegant methods exist, and that's what I'd like to see.
#Create test Array
#9472 - 9727 as HTML Entities (unicode box chars)
range = (9472..9727).to_a.map{|u| "&##{u};" }
Assuming we have a list of mod's and join chars, we have to stipulate that mods increase in value as the list progresses.
mod_joins = [{m:1, c:",", m:12, c:"<br/>"]
Now process the range with mod_joins
processed = range.each_with_index.map { |e, i|
m = nil
mods.reverse_each {|j|
m = j and break if i % j[:m] == 0
}
# use the lowest mod for index 0
m = mods[0] if i == 0
m = nil ? e : "#{e}#{m[:c]}"
}
#output the result string
puts processed.join ""
From this we have a list of htmlEntities, separated by , unless it's index is a 12th modulo in which case it's a <br/>
So, I'm interested for ways this can be done more elegantly, primarily in functional languages like Haskell, F#, Common Lisp (Scheme, Clojure) etc. but also cool ways to achieve this in general purpose languages that have list comprehension extensions such as C# with Linq, Ruby and Python or even Perl.
Here's a pure-functional version written in Python. I'm sure it can be adapted easily enough to other languages.
import itertools
def calcsep(num, sepspecs):
'''
num: current character position
sepspecs: dict containing modulus:separator entries
'''
mods = reversed(sorted(sepspecs))
return sepspecs[next(x for x in mods if num % x == 0)]
vector = [str(x) for x in range(12)]
result = [y for ix, el in enumerate(vector)
for y in (calcsep(ix, {1:'.', 3:',', 5:';'}), el)]
print ''.join(itertools.islice(result, 1, None))
Here’s a simpler and more readable solution in Ruby
array = (9472..9727).map{|u|"&##{u};"}
array.each_slice(12).collect{|each|each.join(",")}.join("<br/>")
or for the general case
module Enumerable
def fancy_join(instructions)
return self.join if instructions.empty?
separator = instructions.delete(mod = instructions.keys.max)
self.each_slice(mod).collect{|each|each.fancy_join(instructions.dup)}.join(separator)
end
end
range = (9472..9727).map{|u|"&##{u};"}
instructions = {1=>",",12=>"<br/>"}
puts array.fancy_join(instructions)

Resources