Matching an element in an unknown sequence location using structural pattern matching in Python 3.10 - python-3.10

Is there any clever way to match on an element in an unknown location in a sequence of unknown length using structural pattern matching in Python 3.10?
Below is a non-working example illustrating what I'd like to do.
match [1, 2, "3", 4, 5]:
case [*before, str() as str_found, *after]:
print(f"Found string: {str_found}")
If you try to use a guard clause, the match isn't captured:
match [1, 2, "3", 4, 5]:
case [*elem] if any(isinstance(el, str) for el in elem):
print("Found string, but I can't tell you its value.")
If the length is known, an or pattern could be used, though it's not pretty:
match [1, 2, "3"]:
case [*_, str() as str_found] | [str() as str_found, *_] | [_, str() as str_found, _]:
print(f"Found string: {str_found}")
Based on answers and comments to other questions about structural pattern matching, I anticipate lots of responses informing me that structural pattern matching isn't the right tool for the job. I know my example doesn't showcase the benefit of using structural pattern matching for this as opposed to something like a simple for loop, but imagine parsing a nested dict and list structure resulting from a json.load(). In any case, my question isn't what the right tool is, but simply whether it can be done with this tool.

This is going to trigger some people, but here you go;
match [1, 2, "3", 4, 5]:
case xs if s:= next((x for x in xs if isinstance(x, str)), False):
print("Found string", repr(s))

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

Array method versus hashes

I have an object (returned from and API) that is either a hash or an array of hashes. I want to enclose it in an array if it is not already an array.
I tried to apply Array on it, which functions in an expected way with numbers or arrays:
Array(1) # => [1]
Array([1, 2]) # => [1, 2]
Array([{a: 1}, {b: 2}]) # => [{:a=>1}, {:b=>2}]
but it fails with hashes:
Array({a: 1}) # => [[:a, 1]]
which should be [{:a=>1}].
Alternatively, I could add a type check:
responses = [responses] if responses.is_a?(Hash)
Is there a better solution?
ActiveSupport introduces Array#wrap that does exactly what you want:
Array.wrap(responses)
I personally prefer to never use any Rails helpers for many reasons, so I would stick with [responses].flatten, or, even better, with the most explicit version:
case responses
when Hash then [responses]
when Array then responses
else raise "shit happened"
end
As #mudasobwa suggested, [responses].flatten is perhaps the cleanest solution:
[{a: 1}].flatten #=> [{:a=>1}]
[[{a: 1}, {b: 2}]].flatten #=> [{:a=>1}, {:b=>2}]
Clearly this inconsistent response format is not a great API design; but that's unfortunately the nature of working with external resources...
If each hash in the above array does represent a unique object, then I would leave that code as-is. However, if you actually have a different hash for each attribute of a single entity (?!), then you could further clean up the API response as follows:
[{a: 1}].flatten.reduce(:merge) #=> {:a=>1}
[[{a: 1}, {b: 2}]].flatten.reduce(:merge) #=> {:a=>1, :b=>2}
I want to enclose it in an array if it is not already an array.
What about:
result = [result] unless result.is_a? Array
Alternatively, using try_convert:
result = Array.try_convert(result) || [result]

Ruby : Choosing between each, map, inject, each_with_index and each_with_object

When I started writing Ruby many years ago, it took me a while to understand the difference between each and map. It only got worse when I discovered all the other Enumerable and Array methods.
With the help of the official documentation and many StackOverflow questions, I slowly began to understand what those methods did.
Here is what took me even longer to understand though :
Why should I use one method or another?
Are there any guidelines?
I hope this question isn't a duplicate : I'm more interested in the "Why?" than the "What?" or "How?", and I think it could help Ruby newcomers.
A more tl;dr answer:
How to choose between each, map, inject, each_with_index and each_with_object?
Use #each when you want "generic" iteration and don't care about the result. Example - you have numbers, you want to print the absolute value of each individual number:
numbers.each { |number| puts number.abs }
Use #map when you want a new list, where each element is somehow formed by transforming the original elements. Example - you have numbers, you want to get their squares:
numbers.map { |number| number ** 2 }
Use #inject when you want to somehow reduce the entire list to one single value. Example - you have numbers, you want to get their sum:
numbers.inject(&:+)
Use #each_with_index in the same situation as #each, except you also want the index with each element:
numbers.each_with_index { |number, index| puts "Number #{number} is on #{index} position" }
Uses for #each_with_object are more limited. The most common case is if you need something similar to #inject, but want a new collection (as opposed to singular value), which is not a direct mapping of the original. Example - number histogram (frequencies):
numbers.each_with_object({}) { |number, histogram| histogram[number] = histogram[number].to_i.next }
Which object can I use?
First, the object you're working with should be an Array, a Hash, a Set, a Range or any other object that respond to each. If it doesn't, it might be converted to something that will. You cannot call each directly on a String for example, because you need to specify if you'd like to iterate over each byte, character or line.
"Hello World".respond_to?(:each)
#=> false
"Hello World".each_char.respond_to?(:each)
#=> true
I want to calculate something with each element, just like with a for loop in C or Java.
If you want to iterate over each element, do something with it and not modify the original object, you can use each. Please keep reading though, in order to know if you really should.
array = [1,2,3]
#NOTE: i is a bound variable, it could be replaced by anything else (x, n, element). It's a good idea to use a descriptive name if you can
array.each do |i|
puts "La"*i
end
#=> La
# LaLa
# LaLaLa
It is the most generic iteration method, and you could write any of the other mentioned methods with it. We will actually, for pedagogical purposes only. If you spot a similar pattern in your code, you could probably replace it with the corresponding method.
It is basically never wrong to use each, it is almost never the best choice though. It is verbose and not Ruby-ish.
Note that each returns the original object, but this is rarely (never?) used. The logic happens inside the block, and should not modify the original object.
The only time I use each is:
when no other method would do. The more I learn about Ruby, the less often it happens.
when I write a script for someone who doesn't know Ruby, has some programming experience (e.g. C, Fortran, VBA) and would like to understand my code.
I want to get an Array out of my String/Hash/Set/File/Range/ActiveRecord::Relation
Just call object.to_a.
(1..10).to_a
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
"Hello world".each_char.to_a
#=> ["H", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d"]
{:a => 1, :b => 2}.to_a
#=> [[:a, 1], [:b, 2]]
Movie.all.to_a #NOTE: Probably very inefficient. Try to keep an ActiveRecord::Relation as Relation for as long as possible.
#=> [Citizen Kane, Trois couleurs: Rouge, The Grapes of Wrath, ....
Some methods described below (e.g. compact, uniq) are only defined for Arrays.
I want to get a modified Array based on the original object.
If you want to get an Array based on the original object, you can use map. The returned object will have the same size as the original one.
array = [1,2,3]
new_array = array.map do |i|
i**2
end
new_array
#=> [1, 4, 9]
#NOTE: map is often used in conjunction with other methods. Here is the corresponding one-liner, without creating a new variable :
array.map{|i| i**2}
#=> [1, 4, 9]
# EACH-equivalent (For pedagogical purposes only):
new_array = []
array.each do |i|
new_array << i**2
end
new_array
#=> [1, 4, 9]
The returned Array will not replace the original object.
This method is very widely used. It should be the first one you learn after each.
collect is a synonym of map. Make sure to use only one of both in your projects.
I want to get a modified Hash based on the original Hash.
If your original object is a Hash, map will return an Array anyway. If you want a Hash back :
hash = {a: 1, b: 2}
hash.map{|key, value| [key, value*2]}.to_h
#=> {:a=>2, :b=>4}
# EACH-equivalent
hash = {a: 1, b: 2}
new_hash = {}
hash.each do |key,value|
new_hash[key]=value*2
end
new_hash
#=> {:a=>2, :b=>4}
I want to filter some elements.
I want to remove nil elements
You can call compact. It will return a new Array without the nil elements.
array = [1,2,nil,4,5]
#NOTE: array.map{|i| i*2} Would raise a NoMethodError
array.compact
# => [1, 2, 4, 5]
# EACH-equivalent
new_array = []
array.each do |integer_or_nil|
new_array << integer_or_nil unless integer_or_nil.nil?
end
new_array
I want to write some logic to determine if an element should be kept in the new Array
You can use select or reject.
integers = (1..10)
integers.select{|i| i.even?}
# => [2, 4, 6, 8, 10]
integers.reject{|i| i.odd?}
# => [2, 4, 6, 8, 10]
# EACH-equivalent
new_array = []
integers.each do |i|
new_array << i if i.even?
end
new_array
I want to remove duplicate elements from your Array
You can use uniq :
letters = %w(a b a b c)
letters.uniq
#=> ["a", "b", "c"]
# EACH-equivalent
uniq_letters = []
letters.each do |letter|
uniq_letters << letter unless uniq_letters.include?(letter)
end
uniq_letters
#TODO: Add find/detect/any?/all?/count
#TODO: Add group_by/sort/sort_by
I want to iterate over all the elements while counting from 0 to n-1
You can use each_with_index :
letters = %w(a b c)
letters.each_with_index do |letter, i|
puts "Letter ##{i} : #{letter}"
end
#=> Letter #0 : a
# Letter #1 : b
# Letter #2 : c
#NOTE: There's a nice Ruby syntax if you want to use each_with_index with a Hash
hash = {:a=>1, :b=>2}
hash.each_with_index{|(key,value),i| puts "#{i} : #{key}->#{value}"}
# => 0 : a->1
# 1 : b->2
# EACH-equivalent
i = 0
letters.each do |letter|
puts "Letter ##{i} : #{letter}"
i+=1
end
each_with_index returns the original object.
I want to iterate over all the elements while setting a variable during each iteration and using it in the next iteration.
You can use inject :
gauss = (1..100)
gauss.inject{|sum, i| sum+i}
#=> 5050
#NOTE: You can specify a starting value with gauss.inject(0){|sum, i| sum+i}
# EACH-equivalent
sum = 0
gauss.each do |i|
sum = sum + i
end
puts sum
It returns the variable as defined by the last iteration.
reduce is a synonym. As with map/collect, choose one keyword and keep it.
I want to iterate over all the elements while keeping a variable available to each iteration.
You can use each_with_object :
letter_ids = (1..26)
letter_ids.each_with_object({}){|i,alphabet| alphabet[("a".ord+i-1).chr]=i}
#=> {"a"=>1, "b"=>2, "c"=>3, "d"=>4, "e"=>5, "f"=>6, "g"=>7, "h"=>8, "i"=>9, "j"=>10, "k"=>11, "l"=>12, "m"=>13, "n"=>14, "o"=>15, "p"=>16, "q"=>17, "r"=>18, "s"=>19, "t"=>20, "u"=>21, "v"=>22, "w"=>23, "x"=>24, "y"=>25, "z"=>26}
# EACH-equivalent
alphabet = {}
letter_ids.each do |i|
letter = ("a".ord+i-1).chr
alphabet[letter]=i
end
alphabet
It returns the variable as modified by the last iteration. Note that the order of the two block variables is reversed compared to inject.
If your variable is a Hash, you should probably prefer this method to inject, because h["a"]=1 returns 1, and it would require one more line in your inject block to return a Hash.
I want something that hasn't been mentioned yet.
Then it's probably okay to use each ;)
Notes :
It's a work in progress, and I would gladly appreciate any feedback. If it's interesting enough and fit in one page, I might extract a flowchart out of it.

Difference between array<<element and array.push(element)? or string<<"something" and string+"something"? in Ruby

Before judging me for an irrelevant question, I'll safeguard myself, that I know << is a bitwise operator. However, in both cases (array, string) it operates as just adding / concatenating values.
Any tip for clarifying whether there's difference if we use array<
Thanks
However, in both cases (array, string) it operates as just adding /
concatenating values.
It makes no difference "result-wise" - in both cases you get a value containing both operands (in that or another form).
The difference shows up in the way operands are impacted:
one performs in-place mutating
second is simply concatenating without changing the original strings.
Consider the following examples:
a = 'a'
b = 'b'
Now:
# concatenation - no changes to original strings
a + b #=> "ab"
a #=> "a"
b #=> "b"
Whereas:
# mutation - original string is changed in-place
a << b #=> "ab"
a #=> "ab"
Same goes with arrays:
# concatenation - no changes to original arrays
a = ['a'] #=> ["a"]
b = ['b'] #=> ["b"]
a + b #=> ["a", "b"]
a #=> ["a"]
b #=> ["b"]
# mutation - original array is changed in-place
a << b #=> ["a", ["b"]]
a #=> ["a", ["b"]]
As to Array#push and Array#<< - they do the same thing.
Firstly, << is not a bit-wise operator. Nor is :<< or "<<". The first is not a Ruby object or keyword. :<< is a symbol and "<<" is a string. Fixnum#<<, by constrast, is a bit-wise operator, implemented as an instance method on the class Fixnum.
You may argue that it's obvious what you meant, but it's not. Many classes have instance methods of the same name that are unrelated. Several classes, for example, have methods called "<<", "+", "size", "replace", "select", "each" and on and on. The only way to speak meaningfully of an instance method, therefore, is to also give the class on which it is defined.
What is an "operator" in Ruby? Frankly, I don't know. I've never found a definition. Whatever it is, however, most of them are implemented as instance methods.
Many of Ruby's core methods have names that may seem unusual to those coming from other languages. Examples are "<<", "+" and "&". The important thing to remember is that these are perfectly-valid names. Let's try using them as you would any other method:
[1,2,3].<<(4) #=> [1, 2, 3, 4]
"cat".+("hat") #=> "cathat"
[1,2,3].&([2,4]) #=> [2]
The head Ruby monk knew that his disciples would prefer to write these as follows:
[1,2,3] << 4
"cat" + "hat"
[1,2,3] & [2,4]
so he said "OK", which when translated from Japanese to English means "OK". He simply designed the Ruby parser so that when it saw the later form it would convert the expression to the standard form before parsing it further (or something like that). This has come to be called syntactic sugar. (Syntactic sugar doesn't allow you to write "cat" concat "hat", however--it only applies to names that are made up of symbols.)
My point with Ruby's operators is that most are implement with garden-variety methods, albeit methods with odd-sounding names. Yes, there are methods String#+ and Array#+ but they are completely unrelated to each other. If they were instead named String#str_add and Array#arr_add and used like so:
"abc".str_add("def")
[1,2,3].arr_add([2,4])
you probably wouldn't be asking the question you've raised.

Resources