Ruby Basics: Pop Method in Array - arrays

I'm working my way through Learning Ruby the Hard Way online; I've just finished the 26th exercise which was a "test" whereby you fixed someone's broken code.
My problem came with using an argument with the pop method. I'm familiar with the basics but the correct answer meant changing the argument from "-1" to "1", and I'm not sure what it means, exactly.
The line in question is:
def puts_last_word(words)
word = words.pop(1)
puts word
end
I assume it pops the second element from the array but I would like confirmation or help, whichever is appropriate.

The best confirmation can be had in the documentation of Array#pop: http://rubydoc.info/stdlib/core/1.9.3/Array:pop
According to that, the argument specifies how many elements, counting from the back of the array, to remove.
The only difference between pop() and pop(1) is that the former will return a single element (the deleted one), while the latter will return an array with a single element (again, the deleted one).
Edit: I suppose the reason the test used -1 is to teach you about the difference between array access with #[], where -1 would mean the last element, and methods like pop, that expect an amount, not a position, as their argument.

The argument specifies how many items to pop. If you specify an argument it returns an array whereas not specifying an argument returns just the element:
ruby-1.8.7-p352 :006 > a = [1,2,3]
=> [1, 2, 3]
ruby-1.8.7-p352 :007 > a.pop(1)
=> [3]
ruby-1.8.7-p352 :008 > a = [4,5,6]
=> [4, 5, 6]
ruby-1.8.7-p352 :009 > a.pop(2)
=> [5, 6]
ruby-1.8.7-p352 :010 > a.pop
=> 4

Related

Elixir: check array contains all the values of another array

I have two arrays:
arr1 = [1,2,3]
arr2 = [2,3]
What is the most handy way to check that all values from the arr2 contains in arr1.
If you just want to check if all of the elements from one list are present in the other list, you can simply use -- using the shorter list at the left side of the operator:
iex> [2, 3] -- [1, 2, 3]
[]
If all of the elements from the first list are present in the second one, the result should be an empty list.
Note, however, that this doesn't account for some cases, for instance, if your first list had a duplicate element, and the other list had the element, but just once, you wouldn't get an empty list:
iex> [2, 3, 3] -- [1, 2, 3]
[3]
But in that case, technically, the second list does not contain all of the elements from the first one.
If you would like to just check for presence of the elements, there are other simple solutions, like:
Enum.all?([2, 3, 3], &Enum.member?([1, 2, 3], &1))
Not sure about how efficient that is, though, as for each element of the first list you're checking if it's present in the second one (however, it will stop checking as soon as one element doesn't meet the condition, and the functions from Enum are typically optimized, so it might be good enough)
And yet another option, would be to use MapSet.
You can do:
MapSet.subset?(MapSet.new([2, 3]), MapSet.new([1, 2, 3]))
This will also work for duplicate elements, as MapSets work as sets, so you cannot have duplicate elements in them.

Is there a way I could iterate over elements in Swift while using method names?

let x = [1, 2, 2, 3, 3, 3, 1].reversed()
for element in x.method_name() {
print(element)
}
This returns
Value of type 'ReversedCollection<[Int]>' has no member 'method_name'.
Why? How do I reference the method I have created and have it do the functions I need it to do?
However, if I use the below, the problem seems to disappear. I would just like to pass in an array and do let the function do all, i.e.:
let x = Array([1, 2, 2, 3, 3, 3, 1].reversed())
Just in case you don't fully understand the motivation behind this overload of reversed returning a ReversedCollection instead of an Array, a ReversedCollection is just a "reversed view" of your original array. It is not a reversed copy of the original array. This is to save time and space, like a "lazy" collection. See this post for more details.
This is why you need the Array(...) initialiser to turn the reversed collection back into an array. You are opting out of the laziness.
On the other hand, there is another overload of reversed that returns an Array directly. Normally this overload is not selected because it is defined in a less specific type - Sequence, as opposed to Array. You need to give enough information about the type to use this overload:
let x: [Int] = [1, 2, 2, 3, 3, 3, 1].reversed()

How to access value in a nested array or subarray using a Ruby method?

This is the array:
array = [ 1, 2, 3, [4, 5, 6] ]
Can I use "delete_at" method to delete the "5"?
array.delete_at[x] method
What would the correct syntax be?
Your 'array' has only 4 elements. If it's subarray you probably should do something like that
array[3].delete_at(1)
to delete the second element of subarray that's a fourth element of 'array' array.
Welcome to Stack Overflow!
This one is longer and less efficient but it allows you to select the item to be deleted by value instead of by position (array index). That's useful when you don't know the position.
array.map {|x| x.delete(5) if x.instance_of?(Array); x}

Looking at a hash as an array?

I found this example of using #any? on a hash a bit tricky:
"With a Hash, you can use these in two ways. Either with one argument that is a 2 element array of the key-value pair. candidate[0] is the key and candidate[1] is its value.
{:locke => 4, :hugo => 8}.any? { |candidate| candidate[1] > 4 }
This returns true because the value of the second candidate :hugo is greater than 4."
Could anyone point me someplace that explains what happened here? I couldn't find a relevant question on SO. Thanks a lot in advance.
If you print candidate it will become easy to understand:
{:locke => 4, :hugo => 8}.any? { |candidate| puts candidate.to_s }
# [:locke, 4]
# [:hugo, 8]
The any? method is treating each key-value pair of the hash as an a two-element array, which means the hash will be treated as an array of arrays.
The block passed to any? (i.e., { |candidate| candidate[1] > 4 }) returns true if any of the the second elements (i.e., 4 and 8) is ever > 4 and false otherwise. 8 > 4, so the result is true.
From the official docs, the any? method:
Passes each element of the collection to the given block. The method
returns true if the block ever returns a value other than false or
nil. If the block is not given, Ruby adds an implicit block of { |obj|
obj } that will cause any? to return true if at least one of the
collection members is not false or nil.
What Hash#any? does is yield arrays of two elements to a given block and return true if the evaluation of the block returned something truthy (not false or nil) and false otherwise.
As for why you get two values if you pass a block with two arguments - this is called unpacking.
def foo
yield [42, 6 * 9]
end
# only one argument, array is not unpacked
foo { |numbers| p numbers } # prints [42, 54]
# two arguments, the array is being unpacked
foo { |x, y| p x, y } # prints 42 \n 54

Groovy each method on list of arrays

I met quite strange behaviour of each method on list of arrays in groovy.
I have given piece of code.
def list = [
[2, "foo"].toArray(),
[4, "bar"].toArray()
]
list.each { def row ->
println(row.length)
}
Which gives me pretty expecting result in console
2
2
Then I did small modification to this code
def list = [
[2, "foo"].toArray(),
[4, "bar"].toArray()
]
list.each { Object[] row ->
println(row.length)
}
And result is
1
1
Because variable row is array with one element which is my original 2 elements array from list.
Is there some explanation for this?
Im using groovy 1.8.8 or 2.1.2
I guess it's a feature rather than a bug :p
Object[] in a closure declaration has a special semantic for variable argument:
From http://groovy.codehaus.org/Closures+-+Formal+Definition:
Groovy has special support for excess arguments. A closure may be declared with its last argument of type Object[]. If the developer does this, any excess arguments at invocation time are placed in this array. This can be used as a form of support for variable numbers of arguments.
In your example, the argument passed to the closure will be wrapped again with a new Object array, containing list as the only element.
As an example:
def list = [
[2, "foo"].toArray(),
[4, "bar"].toArray()
]
def c = {Object[] args -> println args}
c(list)
Output:
[[[2, foo], [4, bar]]]

Resources