0

I am sorry to ask such a basic question, but I have searched for a solution and don't seem to be able to find one that makes sense.

Essentially, I am trying to write a Ruby method that returns the last value of a list (string or array). Here is my code:

def last(x)
x[-1]
end

It actually produces the results I want, but gives me the following error:

`last': wrong number of arguments (given 5, expected 1) (ArgumentError)

I have tried simply adding a wildcard to my expected argument, like so:

def last(*x)
x[-1]
end

This just outputs all values instead of the last one. Anyone got any ideas where I'm going wrong? Again, sorry for the basic question.

4
  • how did you call that method? Also, last is a predefined method in rails, change the name to something else Commented Jan 25, 2017 at 5:15
  • 1
    when it throws that error? do you really pass 5 args? Commented Jan 25, 2017 at 5:15
  • Yeah in one case I passed 5 args, in others I passed a different number. i have an unexpected number of args. Commented Jan 25, 2017 at 5:32
  • Your second attempt is working fine last(1, 2, 3) # => 3 Commented Jan 25, 2017 at 5:56

4 Answers 4

1

When you call your method, you need to pass it a single array. I'm guessing you are passing it several items instead.

>> last(1,2,3,4,5)
ArgumentError: wrong number of arguments (5 for 1)
>> last([1,2,3,4,5])
=> 5
Sign up to request clarification or add additional context in comments.

1 Comment

Here (1,2,3,4,5) is an argument list, while [1,2,3,4,5] is an explicit array.
0

The relevant documentation is here.

The "wildcard" is called "splat operator".

I hope this code makes it clearer :

def last_element_in_array(array) # <-- There must be exactly one parameter
  array[-1]
end

def last_parameter(*parameters) # <-- Any number of parameters
  parameters[-1]
end

p last_element_in_array([1, 2, 3, 4, 5])
#=> 5
p last_parameter(1, 2, 3, 4, 5)
#=> 5
p last_parameter
#=> nil
p last_parameter([1, 2, 3, 4, 5]) # <-- Only one parameter : an array with 5 elements
#=> [1, 2, 3, 4, 5]
p last_element_in_array(1, 2, 3, 4, 5) # <-- Too many parameters. There should be only 1, and it should be an Array.
#=> in `last_element_in_array': wrong number of arguments (given 5, expected 1) (ArgumentError)

2 Comments

Thanks so much for this. This all makes sense. In Codewars it is asking me to find either the final character if it is a string, or the final value if it is an array. So this will work if I am looking for the final value in an array, but will only give me the final letter if I do not use the splat operator, but then I get the error message. I'm going to spend some time on it but really appreciate the help.
@falz3tta : I'm not sure I understand. Could you please update your question with the exact desired syntax for string and array, and show what the expected result would be?
0

The .last allready is a method for collections like an Array. But I think I see what you want, a generic method for both Array and String. and it needs to be able to accept both a various number of arguments (Array of args) as well as an Array itself.

If you study the results below you see what goes wrong with the various versions You would have to add the .last method to String but then you are still in trouble when you pass an Array, so take a look at the last solution. It first flattens any arrays and gives the .last element, then it looks at the class of the last element, in case it's a String it [-1] returns the last character, otherwise just the number Arguments other than String or Array that don't support .last will still give an error I run this from my editor, not irb so I use p here to do some simple debugging. Why p instead of puts ? Because it inspects an object and prints arrays on one line.

The [__LINE__] construct is to print the linenumber to see which results you are seeing I left them in place so that you can try this simple debugging technique.

You would better call this method otherswise (eg last_of) to avoid confusions with the .last method in some classes.

p [__LINE__,[1, 2, 3].last] # 3

def last(x)
  x[-1]
end

p [__LINE__,last([1, 2, 3])] # 3
#p last(1, 2, 3) # wrong number of arguments (3 for 1) (ArgumentError)
p [__LINE__, last("a string")] # g

def last(*x)
    p [__LINE__, x] 
  x[-1]
end

p [__LINE__, last([1, 2, 3])] # [1, 2, 3]
p [__LINE__, last(1, 2, 3)] # 3
p [__LINE__, last("a string")] # "a string"

def last *x
    e = x.flatten.last # flatten any Arrays 
    case e
      when String 
        e[-1]
      when Fixnum
        e
    end
end

p [__LINE__, last([1, 2, 3])] # 3
p [__LINE__, last(1, 2, 3)] # 3
p [__LINE__, last("a string")] # "g"
p [__LINE__, last(["a string"])] # "g"

Comments

0

It sounds like you want to be able to use this two different ways:

last(:a, :b, :c)
last(my_list_type)

The easiest way to achieve this would be to "splat" the arguments, and then check how many elements you have been given. For example:

def last(*args)
  return args[-1] if args.length > 1
  return args[0][-1] if args.length == 1 && args[0].respond_to?(:length)
  args[0] # because we have been given nothing, or a single, non-list-type item
end

Note the following uses - this may or may not be what you intended, but should give you a good starting point:

last 1,2,3          #=> 3
last [4,5,6]        #=> 6
last 1              #=> 1
last "1"            #=> "1"
last "123"          #=> "3"
last "123", "456"   #=> "456"
last                #=> nil
last []             #=> nil

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.