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)