如何在 Clojure 中进入嵌套列表结构而不引发异常?

问题描述 投票:0回答:1

我想检查嵌套列表结构中的某个位置是否有某个东西,但一开始我不知道该结构的形状。如何检查该事物是否存在而不存在引发异常的风险?

例如:

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

但我宁愿避免异常,所以我想知道是否有没有例外的好方法。

list exception data-structures clojure nested
1个回答
0
投票

这个问题属于“我的数据一团糟;我该如何解决它?”的一般(和流行)类别。有两种基本方法:

  1. 弄清楚如何解决它
  2. 首先防止它变得混乱

根据您的具体情况,两者都可行。人们通常将问题表述为(1),就像你所做的那样;但我强烈建议您首先考虑(2)。这通常并不难,人们通常甚至不会尝试它,因为他们眼前的“下一个”问题是如何处理现在的数据,即已经一团糟了。

要解决混乱的数据,您需要更仔细地定义您期望的混乱类型,因为对于“括号海洋中的某个位置,可能存在一些数据”,没有一刀切的答案。例如,如果由于某种原因,您的数据始终是深度最多为 3 的嵌套列表,并且每个列表最多有 1 个元素,并且最深嵌套的非列表是关键字,那么您所布置的方法将正常工作,尽管它可以变得更方便。但如果这些假设中有任何一个是错误的,您就需要更仔细地处理异常。例如,您需要处理

(foo (:thing))
吗?还是
({:mode :thing})
?排列是无穷无尽的,如果不先定义问题就无法解决问题。

防止数据变得混乱需要采取不同的方法。你是怎么到这里来的?您肯定没有读取包含字符串

(((:thing)))
的文本文件。例如,您可能从某个地方获取了一些数据,这些数据的格式可能至少有一半合理,然后您以某种方式对其进行了转换,结果您不小心将其包装在太多列表中。如果发生了类似的事情,请回去尝试找出如何避免这样做的方法。这可能会导致提出一个关于转换数据的正确方法的新问题。

© www.soinside.com 2019 - 2024. All rights reserved.