【问题标题】:Insert item in list after two elements在两个元素之后插入列表中的项目
【发布时间】:2019-12-28 05:10:33
【问题描述】:

我有清单

[%{A: %{}}, %{B: %{}}, %{C: %{}}]

如何在BC 之间添加%{D: %{}},而不是在索引中,如下所示:

[%{A: %{}}, %{B: %{}}, %{D: %{}}, %{C: %{}}]

【问题讨论】:

  • 您能否更具体地说明您希望如何插入这些内容?您是想说“将 D 放入索引 2”吗?
  • 我改了...我需要在A和B之后插入
  • (fn [a, b | rest], c -> [a, b, c | rest] end).([%{A: %{}}, %{B: %{}}, %{C: %{ }}], %{D: %{}})
  • 发布问题时,请确保您首先提供了MCVE。噪音不会让那些在业余时间试图帮助你的人开心。这里的 MCVE 是:[:a, :b, :c]。所有这些地图只会让问题变得难以理解。
  • @AdamMillerchip Kernel.SpecialForms.with/1? with [a, b | rest] <- [:a, :b, :c], do: [a, b, :d | rest].

标签: elixir list-comprehension


【解决方案1】:

List.insert_at/3 看起来很传统。如果不能使用索引,使用模式匹配怎么样?

iex> [a, b, c] = [%{A: %{}}, %{B: %{}}, %{C: %{}}]
[%{A: %{}}, %{B: %{}}, %{C: %{}}]
iex> d = %{D: %{}}
%{D: %{}}
iex> [a, b, d, c]
[%{A: %{}}, %{B: %{}}, %{D: %{}}, %{C: %{}}]

我猜这个答案假设您知道要插入项目的位置。但它不会在函数中使用该信息。

【讨论】:

    【解决方案2】:

    如果我理解正确,您想在两个具有特定键的映射之间插入一些值,而不是基于索引。如果是这样,您将需要使用递归。像下面这样的东西应该会给你你正在寻找的东西。

    def insert_between(value, [a, b | rest], key1, key2) do
      if Map.has_key?(a, key1) and Map.has_key?(b, key2) do
        [a, value, b | rest]
      else
        [a | insert_between(value, [b | rest], key1, key2)]
      end
    end
    # This is the catch all for the scenario where key1 and key2 are not found
    # directly next to each other.
    def insert_between(_value, list, _key1, _key2) do
      list
    end
    
    iex(2)> insert_between(%{d: :d}, [%{a: :a}, %{b: :b}, %{c: :c}], :b, :c)
    [%{a: :a}, %{b: :b}, %{d: :d}, %{c: :c}]
    

    当您找不到彼此直接相邻的键时,我不知道您想做什么,所以我的版本在这种情况下什么都不做。

    【讨论】:

      【解决方案3】:

      由于问题被标记为,因此这里是Kernel.SpecialForms.for/1 列表理解的答案。

      input = ~w|a b c|a
      
      for e <- input, reduce: [] do
        acc -> if e == :b, do: [:d, :b | acc], else: [e | acc]
      end |> :lists.reverse()
      #⇒ [:a, :b, :d, :c]
      

      或者,不减少:

      for e <- input do
        if e == :b, do: [:d, :b], else: e
      end |> :lists.flatten()
      

      【讨论】:

      • 这个答案的问题在于:如何在两个指定元素之间插入一个元素——而不是如何在指定元素之后插入一个元素。如果input[:a, :b, :x],您的代码将在:b 之后插入元素:d,但不满足插入条件。
      • @DarckBlezzer Elixir 有很好的文档,与在互联网上提问相比,它总是能更快地获得。 hexdocs.pm/elixir/master/Kernel.SpecialForms.html?#for/…
      【解决方案4】:
        def insert_between(a, b, list, x), do: insert_between(a, b, list, x, [])
      
        def insert_between(a, b, [a,b|tail], x, acc) do
          insert_between(a, b, tail, x, [b, x, a | acc])
        end
        def insert_between(a, b, [head|tail], x, acc) do
          insert_between(a, b, tail, x, [head|acc])
        end
        def insert_between(_, _ ,[], _, acc) do
          Enum.reverse(acc)
        end
      

      【讨论】:

      • 这只是我回答的效率较低的版本。如果找到匹配项,当您可以停下来时,为什么总是遍历整个列表?最重要的是,你需要在你的答案中颠倒列表,这意味着你实际上已经完整地浏览了两次列表。
      • 这不是真的。 gist.github.com/ankhers/290f58253dcc0e6237b40a888b047cb6。如果它像你说的那样高效,那么反转100_000_000 大小的列表不需要大约 2 秒。即使它同样有效,在找到匹配项后,您仍然会不必要地遍历整个列表。您还匹配[head|tail] 并将列表重新创建为[head|tail]。我不确定是否对此进行了优化,但写[_ | _] = list 会更惯用。
      猜你喜欢
      • 1970-01-01
      • 2012-02-01
      • 2015-09-11
      • 2012-09-21
      • 2021-06-27
      • 2017-01-15
      • 2020-07-09
      • 2016-03-12
      • 2011-01-16
      相关资源
      最近更新 更多