我想检查嵌套列表结构中的某个位置是否有某个东西,但一开始我不知道该结构的形状。如何检查该事物是否存在而不存在引发异常的风险?
例如:
:thing
一开始应该是三层深,像这样:
(def st '(((:thing))))
我可以用
(-> st first first first)
到达它。但是,如果列表结构不够深,则会引发异常。
如何有效检查其存在?到目前为止我的解决方案是这样的:
(if (list? st)
(let [in1 (first st)]
(if (list? in1)
(let [in2 (first in1)]
(if (list? in2)
(= :thing (first in2))
false))
false))
false)
它很难看并且容易出错,所以我希望有一个更好的解决方案。 IMO,最大的障碍是
first
如果它没有得到序列,则会抛出异常。因此,一种方法是拥有一些行为类似于 first
但不会抛出异常的东西;一种方法是像这样捕获异常:
(try (= :thing (-> st first first first))
(catch IllegalArgumentException _
false))
但我宁愿避免异常,所以我想知道是否有没有例外的好方法。
这个问题属于“我的数据一团糟;我该如何解决它?”的一般(和流行)类别。有两种基本方法:
根据您的具体情况,两者都可行。人们通常将问题表述为(1),就像你所做的那样;但我强烈建议您首先考虑(2)。这通常并不难,人们通常甚至不会尝试它,因为他们眼前的“下一个”问题是如何处理现在的数据,即已经一团糟了。
要解决混乱的数据,您需要更仔细地定义您期望的混乱类型,因为对于“括号海洋中的某个位置,可能存在一些数据”,没有一刀切的答案。例如,如果由于某种原因,您的数据始终是深度最多为 3 的嵌套列表,并且每个列表最多有 1 个元素,并且最深嵌套的非列表是关键字,那么您所布置的方法将正常工作,尽管它可以变得更方便。但如果这些假设中有任何一个是错误的,您就需要更仔细地处理异常。例如,您需要处理
(foo (:thing))
吗?还是({:mode :thing})
?排列是无穷无尽的,如果不先定义问题就无法解决问题。
防止数据变得混乱需要采取不同的方法。你是怎么到这里来的?您肯定没有读取包含字符串
(((:thing)))
的文本文件。例如,您可能从某个地方获取了一些数据,这些数据的格式可能至少有一半合理,然后您以某种方式对其进行了转换,结果您不小心将其包装在太多列表中。如果发生了类似的事情,请回去尝试找出如何避免这样做的方法。这可能会导致提出一个关于转换数据的正确方法的新问题。