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.

16
  • 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? Commented Jul 17, 2014 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. Commented Jul 17, 2014 at 16:43
  • This smells like homework. Commented Jul 17, 2014 at 16:53
  • 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? Commented Jul 17, 2014 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. Commented Jul 17, 2014 at 19:11

3 Answers 3

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
Sign up to request clarification or add additional context in comments.

6 Comments

That method returns 10.
10.times { array.delete_if { |x| x.is_a?(Integer) } }
TypeError: no implicit conversion from nil to integer when there are fewer than 10 digits in the array.
This runs i.is_a?(Integer) 99 times before erroring.
@fbonetti The first run deletes all integers.
|
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]

1 Comment

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.
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).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.