1

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.

Mahesh Mesta
  • 169
  • 7
  • 1
    This sounds like a homework/interview question? – Pascal Jul 11 '17 at 08:58
  • @pascal betz Are we not allowed to ask homework or interview questions with tried and tested solutions and check if there are better solutions to it? – Mahesh Mesta Jul 11 '17 at 09:07
  • I don't understand. Why are you downvoting my answer? I have given my solution to it and am asking a better one. What sort of programming questions can we ask, if this question is wrong? There are millions of such questions in StackOverflow and helpful people are giving solutions to such questions. What was so offensive of my question? – Mahesh Mesta Jul 11 '17 at 09:09
  • Take a look at [Fastest algorithm for circle shift N sized array for M position](https://stackoverflow.com/questions/876293/fastest-algorithm-for-circle-shift-n-sized-array-for-m-position). It's an algorithm question so there's only psuedocode but might be enough to get you going and I believe the example in the question is the same as your expected input/output – Simple Lime Jul 11 '17 at 09:10
  • 2
    It's gonna be real hard to not use any built-in method, since it's pretty much all Ruby has. – Eric Duminil Jul 11 '17 at 09:18
  • Not using any built-in methods is like building a house without using any tools. – Cary Swoveland Jul 13 '17 at 05:45
  • Cary Swoveland, I understand. Its just that since I am learning Ruby, I wanted to try it with plain logic first. – Mahesh Mesta Jul 13 '17 at 06:05

4 Answers4

4

The standard way is:

[1, 2, 3, 4, 5, 7, 8, 9].rotate(-3) #=> [7, 8, 9, 1, 2, 3, 4, 5]
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
sawa
  • 165,429
  • 45
  • 277
  • 381
  • But my question was to remove the last elements and append it to the front of the array. ie. [1, 2, 3, 4, 5, 7, 8, 9] with 3 as the given number should make it [7, 8, 9, 1, 2, 3, 4, 5] – Mahesh Mesta Jul 11 '17 at 12:33
  • 2
    @MaheshMesta you can use `-3` to reverse the direction. – Stefan Jul 11 '17 at 12:41
  • I've taken the liberty of correcting sawa"s answer. (I think it's the first time I've edited *any* answer.) I did so because it needs to be fixed but it could be awhile before sawa reappears. Whenever I use `rotate` I can never remember which way the array will rotate when the argument is positive or negative (so must test). I'm sure that's what happened here. I'll try to remember this in future: "a positive argument means go to the back of the line". Mahesh, please consider removing your comment as it is no longer relevant. – Cary Swoveland Jul 12 '17 at 02:23
1

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)

Simple Lime
  • 10,790
  • 2
  • 17
  • 32
1

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.

Stefan
  • 109,145
  • 14
  • 143
  • 218
0

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

Eric Duminil
  • 52,989
  • 9
  • 71
  • 124