Feature #19840
closed[Proposal] Expand Find pattern to Multiple Find
Description
Hello! I love Ruby's pattern matching features. I would like to propose an expansion of the Find pattern which allows the selection of multiple matching elements of an array.
I often find myself dealing with data like this:
My problem is that I need to retrieve all the id values from the nested array of hashes, and I don't know how many there will be in advance.
It seems that the Find pattern could be expanded from allowing pattern (matching a single element) to *pattern. Examples:
# Base case
case { results: [{ id: 1, name: "foo" }, { id: 2, name: "bar" }] }
in results: [*{ id: ids }]
"matched: #{ids}"
else
"not matched"
end
#=> matched: [1, 2]
# With * at the end (rest of args) - same result
case { results: [{ id: 1, name: "foo" }, { id: 2, name: "bar" }] }
in results: [*{ id: ids }, *]
"matched: #{ids}"
else
"not matched"
end
#=> matched: [1, 2]
# When one element doesn't match and there is no *rest
case { results: [{ name: "foo" }, { id: 2, name: "bar" }] }
in results: [*{ id: ids }]
"matched: #{ids}"
else
"not matched"
end
#=> not matched
Similarly, *Constant could work to pull out types with an As pattern:
case [1, 2, 3, "string"]
in *Integer => nums, *
"matched: #{nums}"
else
"not matched"
end
#=> matched: [1, 2, 3]
Other patterns would work in the same way. Essentially, this expands the concept of * in pattern matching to mean "a variable number of things matching subpattern". Today, the only pattern supported by * is a variable binding - but it could be any of the other subpatterns as well.
This proposal does imply that this would work:
To me, the * represents the variable number of matches, so the syntax makes intuitive sense. But others may have different opinions about *^ being adjacent.
It may also imply this would work, though we could restrict the number of non-variable patterns (in other words, patterns that have the possibility of not matching) to 1 per Array so that this isn't possible.. I'm not sure something like this would be useful or clear.
This feature feels like the missing piece of the Find pattern to me - I often want to "Find Multiple". If others agree, I would be happy to contribute by working on this feature and creating a pull request.
Updated by mame (Yusuke Endoh) almost 3 years ago
- Assignee set to ktsj (Kazuki Tsujimoto)
Updated by hsbt (Hiroshi SHIBATA) over 2 years ago
- Status changed from Open to Assigned
Updated by ktsj (Kazuki Tsujimoto) about 2 years ago
- Status changed from Assigned to Feedback
Sorry for late response.
I disagree with this suggestion.
I implemented this feature in the pattern-match gem, a PoC library for pattern matching.
match({ results: [{ id: 1, name: "foo" }, { id: 2, name: "bar" }] }) do
with Hash.(results: _[*Hash.(id: ids)]) do
"matched: #{ids}"
end
with _ do
"not matched"
end
end
#=> matched: [1, 2]
My conclusion was that the complexity of the specification and implementation was not worth it for the frequency of use.
If there are strong use cases, I will reconsider.