长生不老药删除嵌套的元素

时间:2018-08-08 09:58:12

标签: enums nested elixir

我有一个包含映射和数组的嵌套结构,我想保留嵌套数组的第一个元素<script src="https://code.jquery.com/jquery-3.0.0.js"></script> <link href="https://unpkg.com/video.js/dist/video-js.css" rel="stylesheet"> <script src="https://unpkg.com/video.js/dist/video.js"></script> <script src="https://unpkg.com/videojs-contrib-hls/dist/videojs-contrib-hls.js"></script> <video id="example-video" class="video-js vjs-default-skin" controls preload="auto" height="225" width="auto"> <source src="https://video-dev.github.io/streams/x36xhzz/x36xhzz.m3u8" type="application/x-mpegURL"> </video> <script> var player = videojs('example-video'); player.play(); </script> 。 我想保留大部分结构,并用它们的第一个元素替换嵌套数组。可以说我有一个基本数组Enum.at(0),它包含一个数组oldstruct,该数组本身包含一个数组a。我要删除b中除第一个项外的所有项,并对a内的数组b做同样的事情。在JS中,我可以使用以下代码进行操作:

a

我如何在Elixir中做到这一点?

编辑: 这就是我想用Elixir解决的方法:

var newStruct = [];
for (var i = 0; i < oldstruct.length; i++) {
  newStruct.push(oldStruct[i]);
  newStruct[i].a = [];
  newStruct[i].a.push(oldStruct[i].a[0]);
  newStruct[i].a[0].b = [];
  newStruct[i].a[0].b.push(oldStruct[i].a[0].b[0]);
}

我想要什么:

result
|> Enum.filter(fn(x) ->
  Enum.filter(x.chat_users, fn(y) ->
    case y == Enum.at(x.chat_users, 0) do
      true ->
        Enum.filter(y.chat_messages, fn(z) ->
          case z == Enum.at(y.chat_messages, 0) do
            true -> true
            false -> false
          end
        end)
      false ->  false
    end
  end)
 true
end)

我得到了什么

[%Chat.Chat{ chat_users: [%Chat.ChatUser{
  chat_messages: [%Chat.ChatMessage{text: "some text}]}],
  {other_property: ...}},
 %Chat.Chat{ chat_users: [%Chat.ChatUser{
  chat_messages: [%Chat.ChatMessage{text: "some text}]}],
  {other_property: ...}}]

因此,根据我的实际结构,我得到了一个带有一些属性的聊天数组,一个带有chatuser的数组和一个每个chatuser具有chat_messages的数组,我想保留第一个chatuser和第一个chatmessage作为保留的chatuser。

适应Igor的答案后的解决方案:

[%Chat.Chat{ chat_users: [%Chat.ChatUser{
  chat_messages: [%Chat.ChatMessage{text: "some text},
  %Chat.ChatMessage{text: "some text},
  %Chat.ChatMessage{text: "some text}]},
  %Chat.ChatUser{
  chat_messages: [%Chat.ChatMessage{text: "some text},
  %Chat.ChatMessage{text: "some text}],
  {other_property: ...}}]},
  %Chat.Chat{ chat_users: [%Chat.ChatUser{
  chat_messages: [%Chat.ChatMessage{text: "some text},
  %Chat.ChatMessage{text: "some text},
  %Chat.ChatMessage{text: "some text}]},
  %Chat.ChatUser{
  chat_messages: [%Chat.ChatMessage{text: "some text},
  %Chat.ChatMessage{text: "some text}],
  {other_property: ...}}]}]

3 个答案:

答案 0 :(得分:1)

假设您具有以下结构,可以满足您的描述:

initial = [
  %{a: [%{b: [1,2,3]}, 1], c: 0 },
  %{a: [%{b: [1,2,3]}, 1], c: 0 },
  %{a: [%{b: [1,2,3]}, 1], c: 0 },
  %{a: [%{b: [1,2,3]}, 1], c: 0 },
]

我们只想在:a:b键下使用列表的第一个元素。

然后Elixir中的以下行解决了该问题:

final =
  initial
    |> Enum.map(fn map_with_a ->
      Map.update!(map_with_a, :a, fn list_with_bs ->
        map_with_b =
          list_with_bs
          |> List.first
          |> Map.update!(:b, & [List.first(&1)])
        [map_with_b]
      end)
    end)

IO.puts(inspect(final))

只需遍历列表并使用Map.update!/3函数更新地图值。

输出为:

[
  %{a: [%{b: [1]}], c: 0},
  %{a: [%{b: [1]}], c: 0},
  %{a: [%{b: [1]}], c: 0},
  %{a: [%{b: [1]}], c: 0}
]

答案 1 :(得分:0)

假设这组数据,类似于Igor的示例:

initial = [
  %{a: [%{b: [1,2,3]}, 1], c: 0 },
  %{a: [%{b: [1,2,3]}, 1], c: 0 },
  %{a: [%{b: [1]}, 1], c: 0 },
  %{a: [%{b: []}, 1], c: 0 },
]

另一种可能性是利用传递给Enum.map的匿名函数上的多个函数头,尽管根据口味,它的可读性可能较低:

Enum.map(initial, fn
    (%{a: [%{b: [h | _]} | _]} = element) -> Map.put(element, :a,  [%{b: [h]}])
    (%{a: _} = element) -> Map.put(element, :a, [])
    (element) -> element
end)

[
  %{a: [%{b: [1]}], c: 0},
  %{a: [%{b: [1]}], c: 0},
  %{a: [%{b: [1]}], c: 0},
  %{a: [], c: 0}
]

答案 2 :(得分:0)

这是Kernel.get_and_update/3的完美用例,具有作为键的功能(感谢@ igor-drozdov的初始数据):

get_and_update_in(
  initial,
  [Access.all(), :a,
   fn :get_and_update, [%{b: [h|_]}|tail], _next ->
     {h, [%{b: [h]}|tail]}
   end],
  & &1)
#⇒ {[1, 1, 1, 1],
# [
#   %{a: [%{b: [1]}, 1], c: 0},
#   %{a: [%{b: [1]}, 1], c: 0},
#   %{a: [%{b: [1]}, 1], c: 0},
#   %{a: [%{b: [1]}, 1], c: 0}
# ]}

Access非常强大,在这种情况下,通常会淘汰通用映射器。