我有一个包含映射和数组的嵌套结构,我想保留嵌套数组的第一个元素<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: ...}}]}]
答案 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
非常强大,在这种情况下,通常会淘汰通用映射器。