diff --git a/CHANGES.rst b/CHANGES.rst index 76f29ff356..4266957a93 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -27,6 +27,7 @@ Enhancements * a function `evaluate_predicate` allows for a basic predicate evaluation using `$Assumptions`. * ``Attributes`` accepts a string parameter. +* ``Cases`` accepts Heads option. Issue #1302. * ``ColorNegate`` for colors is supported. * ``D`` and ``Derivative`` improvements. * ``FileNames`` returns a sorted list (#1250). diff --git a/mathics/builtin/lists.py b/mathics/builtin/lists.py index dde8f65b9c..5e857193cf 100644 --- a/mathics/builtin/lists.py +++ b/mathics/builtin/lists.py @@ -25,6 +25,7 @@ MessageException, NegativeIntegerException, CountableInteger, + ) from mathics.core.expression import ( Expression, @@ -50,7 +51,7 @@ from mathics.core.expression import min_prec, machine_precision from mathics.core.expression import structure from mathics.core.evaluation import BreakInterrupt, ContinueInterrupt, ReturnInterrupt -from mathics.core.rules import Pattern +from mathics.core.rules import Pattern, Rule from mathics.core.convert import from_sympy from mathics.builtin.numbers.algebra import cancel from mathics.algorithm.introselect import introselect @@ -1970,10 +1971,14 @@ def apply_pattern(self, items, sel, pattern, evaluation): class Cases(Builtin): """
-
'Cases[$list$, $pattern$]' -
returns the elements of $list$ that match $pattern$. -
'Cases[$list$, $pattern$, $ls$]' -
returns the elements matching at levelspec $ls$. +
'Cases[$list$, $pattern$]' +
returns the elements of $list$ that match $pattern$. + +
'Cases[$list$, $pattern$, $ls$]' +
returns the elements matching at levelspec $ls$. + +
'Cases[$list$, $pattern$, Head->$bool$]' +
Match including the head of the expression in the search.
>> Cases[{a, 1, 2.5, "string"}, _Integer|_Real] @@ -1981,6 +1986,14 @@ class Cases(Builtin): >> Cases[_Complex][{1, 2I, 3, 4-I, 5}] = {2 I, 4 - I} + Find symbols among the elements of an expression: + >> Cases[{b, 6, \[Pi]}, _Symbol] + = {b, Pi} + + Also include the head of the expression in the previous search: + >> Cases[{b, 6, \[Pi]}, _Symbol, Heads -> True] + = {List, b, Pi} + #> Cases[1, 2] = {} @@ -2008,13 +2021,25 @@ class Cases(Builtin): "Cases[pattern_][list_]": "Cases[list, pattern]", } - options = {"Heads": "False",} + options = { + "Heads": "False", + } def apply(self, items, pattern, ls, evaluation, options): "Cases[items_, pattern_, ls_:{1}, OptionsPattern[]]" if items.is_atom(): return Expression(SymbolList) + from mathics.builtin.patterns import Matcher + if ls.has_form("Rule", 2): + if ls.leaves[0].get_name() == "System`Heads": + heads = ls.leaves[1].is_true() + ls = Expression("List", 1) + else: + return evaluation.message("Position", "level", ls) + else: + heads = self.get_option(options, "Heads", evaluation).is_true() + try: start, stop = python_levelspec(ls) except InvalidLevelspecError: @@ -2022,10 +2047,7 @@ def apply(self, items, pattern, ls, evaluation, options): results = [] - from mathics.builtin.patterns import Matcher - if pattern.has_form("Rule", 2) or pattern.has_form("RuleDelayed", 2): - from mathics.core.rules import Rule match = Matcher(pattern.leaves[0]).match rule = Rule(pattern.leaves[0], pattern.leaves[1]) @@ -2045,10 +2067,6 @@ def callback(level): results.append(level) return level - # TODO - heads = self.get_option(options, 'Heads', evaluation).is_true() - # heads = False - walk_levels(items, start, stop, heads=heads, callback=callback) return Expression(SymbolList, *results)