2

I have an array in Ruby and I would like to delete the first 10 digits in the array.

array = [1, "a", 3, "b", 2, "c", 4, "d", 5, "a", 1, "z", 7, "e", 21, "q", 30, "a", 4, "t", 7, "m", 5, 1, 2, "q", "s", "l", 13, 46, 31]

It would ideally return

['a', 'b', 'c', 'd', 'a', 'z', 'e', 'q', 0, 'a', 4, t, 7, m, 5 , 1, 2, q, s, 1, 13, 46, 31]

By removing the first 10 digits (1,3,2,4,5,1,7,2,1,3).

Note that 21(2 and 1) and 30(3 and 0) both have 2 digits

Here's what I've tried

digits = array.join().scan(/\d/).first(10).map{|s|s.to_i}
=> [1,3,2,4,5,1,7,2,1,3]
elements = array - digits

This is what I got

["a", "b", "c", "d", "a", "z", "e", 21, "q", 30, "a", "t", "m", "q", "s", "l", 13, 46, 31]

Now it looks like it took the difference instead of subtracting.

I have no idea where to go from here. and now I'm lost. Any help is appreciated.

George Lucas
  • 197
  • 1
  • 8
  • if the last digit is a part of a bigger number (lets, say it is 2 from 3245), what do you want to have in the array? Just 45 or you want to remove the whole number? – Ivaylo Petrov Jul 17 '14 at 16:41
  • I don't want to remove the whole number. Only the first 10 digits, not numbers. Some numbers like 47 have 2 digits. For example 21 and 30 showed up, but they were supposed to be deleted. – George Lucas Jul 17 '14 at 16:43
  • This smells like homework. – the Tin Man Jul 17 '14 at 16:53
  • Indeed, but it was a problem I gave for myself. It's to practice coding. – George Lucas Jul 17 '14 at 16:54
  • George, there's no rush selecting an answer. A quick selection can discourage other, possibly better, answers, and is a bit annoying to those still working on answers when the green checkmark appears. Those asking you to select their answer just want to close the question. Sure, and [pigs might fly](http://idioms.thefreedictionary.com/pigs+might+fly). If you suspect this might be a [pet peeve](http://idioms.thefreedictionary.com/pet+peeve) of mine, you would be correct. – Cary Swoveland Jul 17 '14 at 18:20
  • I was requested to select an answer because I thanked him for his time. I felt like that was the appropriate action. Anyways, I still give up votes to correct answers. – George Lucas Jul 17 '14 at 18:33
  • @GeorgeLucas do you want to convert all numbers to separate digits? – Stefan Jul 17 '14 at 18:34
  • @Stefan - Just delete the first 10 digits, and have the remaining digits appear in their original manner. Only exception would be if the 10th digit deleted was the first digit of a 2 digit number. In that case the 2nd digit would serve as its own element. Isotope had an excellent answer that returned what I was looking for. – George Lucas Jul 17 '14 at 18:38
  • @GeorgeLucas Isotope's answer deletes both, `2` and `0`. In your example output above (*"It would ideally return"*) the remaining numbers are converted to digits, i.e. `13, 46, 31` become `1, 3, 4, 6, 3, 1`. Is that desired? – Stefan Jul 17 '14 at 18:44
  • @Stefan, sorry that was a mistake on my part. I will fix it. The numbers should be 13, 46, 31 – George Lucas Jul 17 '14 at 18:57
  • 2
    The answer I got suggests that digits are supposed to be removed, not numbers. For example from `[1, "a", 3, "b", 2, "c", 4, "d", 5, "a", 1, "z", 7, "e", 21, "q", 3245, "a", 4, "t", 7, "m", 5, 1, 2, "q", "s", "l", 13]` I think that George Lucas wants to get `["a", "b", "c", "d", "a", "z", "e", "q", 245, "a", 4, "t", 7, "m", 5, 1, 2, "q", "s", "l", 13]`. This is my understanding... And the accepted answer produces `["a", "b", "c", "d", "a", "z", "e", "q", "a", "t", 7, "m", 5, 1, 2, "q", "s", "l", 13, 46, 31]`. Is that the expected behavior? – Ivaylo Petrov Jul 17 '14 at 19:01
  • 1
    @Ivaylo - That answer is correct. Digits are supposed to be removed but not numbers. For example say we had a two digit number (50), if the 10th digit is 5 and the 11th digit is 0, than the digit 5 would be removed but the digit 0 would remain. – George Lucas Jul 17 '14 at 19:11
  • If `array = ['a', 123, 45]` and you wanted to delete the first digit only, would you want `['a', 23, 45]` returned? – Cary Swoveland Jul 17 '14 at 20:11
  • George, I can add another pitfall to selecting an answer in haste: as here, it may later become evident that the answer you selected is incorrect. You may want to read the selected answer to [this question](http://meta.stackexchange.com/questions/19448/etiquette-for-selecting-answers). – Cary Swoveland Jul 17 '14 at 21:16
  • Cary - Looks like I might not have handled this correctly. I felt under pressure to accept the answer and that if I didn't I would have received down votes. I'll try not to do that again, but I do have a habit to thank people after answering my question because I appreciate the time they put in. – George Lucas Jul 17 '14 at 21:25
  • This happens a lot to relative newbies who are unfamiliar with SO procedures and etiquette. Have a look at [this faq](http://meta.stackexchange.com/questions/7931/faq-for-stack-exchange-sites), especially the section on selecting answers. – Cary Swoveland Jul 17 '14 at 21:37

3 Answers3

3

To delete 10 numbers:

10.times.each {array.delete_at(array.index(array.select{|i| i.is_a?(Integer)}.first))}
array

To delete 10 digits:

array = [1, "a", 3, "b", 2, "c", 4, "d", 5, "a", 1, "z", 7, "e", 21, "q", 30, "a", 4, "t", 7, "m", 5, 1, 2, "q", "s", "l", 13, 46, 31]
i = 10
while (i > 0) do
    x = array.select{|item| item.is_a?(Integer)}.first
    if x.to_s.length > i
      y = array.index(x)
      array[y] = x.to_s[0, (i-1)].to_i
    else
      array.delete_at(array.index(x))
    end
    i -= x.to_s.length
end
array
TomDunning
  • 4,829
  • 1
  • 26
  • 33
3

Unfortunately not a one-liner:

count = 10
array.each_with_object([]) { |e, a|
  if e.is_a?(Integer) && count > 0
    str = e.to_s                     # convert integer to string
    del = str.slice!(0, count)       # delete up to 'count' characters
    count -= del.length              # subtract number of actually deleted characters
    a << str.to_i unless str.empty?  # append remaining characters as integer if any
  else
    a << e
  end
}
#=> ["a", "b", "c", "d", "a", "z", "e", "q", 0, "a", 4, "t", 7, "m", 5, 1, 2, "q", "s", "l", 13, 46, 31]
Stefan
  • 109,145
  • 14
  • 143
  • 218
  • There might be easier ways to solve this, but nonetheless this answered the question. Therefore it is a good solution. Good answer, the output was as expected. – George Lucas Jul 17 '14 at 19:13
1

I would be inclined to do it like this.

Code

def doit(array, max_nbr_to_delete)
  cnt = 0
  array.map do |e|
    if (e.is_a? Integer) && cnt < max_nbr_to_delete
      cnt += e.to_s.size
      if cnt <= max_nbr_to_delete
        nil
      else
        e.to_s[cnt-max_nbr_to_delete..-1].to_i
      end
    else
      e
    end
  end.compact
end

Examples

array = [ 1, "a", 3, "b", 2, "c", 4, "d", 5, "a", 1, "z", 7, "e", 21, "q",
         30, "a", 4, "t", 7, "m", 5, 1, 2, "q", "s", "l", 13, 46, 31]

doit(array, 10)
  #=> ["a", "b", "c", "d", "a", "z", "e", "q", 0, "a", 4,
  #    "t", 7, "m", 5, 1, 2, "q", "s", "l", 13, 46, 31]
doit(array, 100)
  #=> ["a", "b", "c", "d", "a", "z", "e", "q", "a", "t", "m", "q", "s", "l"]    

Explanation

Each element e of the array that is not an integer is mapped to e.

For each non-negative integer n having d digits, suppose cnt is the number of digits that map has already been removed from the string. There are three possibilities:

  • if cnt >= max_nbr_to_delete, no more digits are to be removed, so e (itself) is returned
  • if cnt + d <= max_nbr_to_delete all d digits of e are to be removed, which is done by mapping e to nil and subsequently removing nil elements
  • if cnt < max_nbr_to_delete and cnt + d > max_nbr_to_delete, e.to_s[cnt+d-max_nbr_to_delete..-1].to_i is returned (i.e. the first cnt+d-max_nbr_to_delete digits of e are removed).
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100