我目前正试图找出遍历List的最佳方法。 遍历是什么意思?
示例:
我有一个用户列表:
userList : List User
userList =
[user, user, user, user]
我有一个currentUser,它必须是userList
之外的用户所以我想要实现的目标是: 我想要像 List.getNext 那样获取userList和当前用户并返回列表中的下一个用户,相对于currentUser
这是我的实施。我觉得这很复杂 - 所以有人知道如何以更好的方式做到这一点吗?
traverseList : List a -> a -> Maybe (Maybe a)
traverseList list currentElement =
let
indexList =
List.indexedMap
(\index element ->
if element == currentElement then
index
else
-1
)
list
currentAsIndex =
let
mayBeIndex =
List.maximum indexList
in
case mayBeIndex of
Just index ->
index
Nothing ->
0
getWanted =
List.map
(\( id, element ) ->
if id == (currentAsIndex + 1) then
Just element
else
Nothing
)
(List.indexedMap (,) list)
|> List.filter
(\element ->
element /= Nothing
)
|> List.head
in
getWanted
解释
我的方法是获取列表,创建给定列表的索引列表(看起来像这样[-1,-1,-1,3,-1,-1])
然后我得到这个列表的最大值 - 因为这给了我当前用户在List.indexedMap中的位置。
然后我将原始作为List.indexedMap迭代并找出下一个(在我们的例子中为4)并返回该元素。否则我什么都不回。
然后我过滤这个Nothings列表,只过滤一个用户,并使用List.head从列表中提取用户。
结果是一个可能(也许是用户)......这不太好......或者?
感谢任何想法以更好的功能方式做这样的事情。
我真的想在功能编程方面做得更好......
答案 0 :(得分:4)
这是一个非常幼稚的递归解决方案:
getWanted : List a -> a -> Maybe a
getWanted list currentElement =
let findNextInList l = case l of
[] -> Nothing
x :: [] -> if x == currentElement
then List.head list
else Nothing
x :: y :: rest -> if x == currentElement
then Just y
else findNextInList (y :: rest)
in
findNextInList list
这里的想法是查看列表的前两个元素,如果第一个是当前元素,则选择第二个元素。如果没有,请再次使用列表的尾部。
必须处理极端情况(您可以为此功能编写至少4个单元测试):
也许有一个更优雅的解决方案,但递归是函数式编程中非常常见的技术,所以我想分享这种方法。
答案 1 :(得分:4)
如果您愿意导入list-extra,可以使用
import List.Extra as LE exposing ((!!))
getNext : a -> List a -> Maybe a
getNext item list =
list
|> LE.elemIndex item
|> Maybe.map ((+) 1)
|> Maybe.andThen ((!!) list)
如果找到的元素是列表中的最后一个,则返回Nothing
答案 2 :(得分:1)
我最喜欢farmio基于图书馆的方法,这也是我将来会使用的方法。
那就是说,对于榆树的新手而不是查看它的库,我以前的方法如下:即索引列表,查找索引(如果搜索到的任何项目),获取下一个索引的项目(如果有的话)
nextUser : List User -> User -> Maybe User
nextUser lst usr =
let
numberedUsers =
List.map2 (\idx u -> ( idx, u )) (List.range 1 (List.length lst)) lst
usrIdx =
List.filter (\( idx, u ) -> u.name == usr.name) numberedUsers
|> List.head
|> Maybe.map Tuple.first
|> Maybe.withDefault -1
in
List.filter (\( idx, u ) -> idx == usrIdx + 1) numberedUsers
|> List.head
|> Maybe.map Tuple.second
使用折叠的另一种方法就是使用折叠。
也许只使用List
代替Array
,...
@foreach($photos as $photo)
<tr data-sortable="{{ $photo->pivot->position }}" data-id="{{ $restaurant->id }}" data-photo-id="{{ $photo->pivot->photo_id }}">
<td>
<i class="fa fa-sort" aria-hidden="true"></i>
</td>
...
</tr>
@endforeach
<script type="text/javascript">
$("#sortable-ui tbody").sortable({
helper: fixHelper,
update: function(event, ui) {
$("#sortable-ui tbody tr").each(function(index){
console.log($(this).data('id')+', '+(index+1));
$.ajax({
url: '{{ route('owner.photo.update.position') }}',
type: 'POST',
data: 'restaurant_id='+$(this).data('id')+'&photo_id='+$(this).data('photo-id')+'&position='+(index+1)
})
.done(function (response) {
console.log(response);
})
.fail(function (jqXhr) {
console.log(jqXhr);
});
});
}
}).disableSelection();
</script>
提供基于索引的访问。
答案 3 :(得分:1)
另一种可能的解决方案:
<form id="form" onSubmit="return validate();" action="" method="post">
我们删除列表的第一个元素,然后将其与原始列表一起压缩以获取元组列表。元组的每个元素都包含当前元素和下一个元素。然后我们过滤该列表,然后选择&#39; next&#39;来自元组的元素并占据最终列表的头部。
答案 4 :(得分:0)
具体问题有一些好的答案。我想提出一种替代模型,因为这种方法有一些缺点:
[user1, user2, user1, user3]
结尾,则轮换将永远不会达到user3
。Maybe
很难正确处理。因此,假设您当前的模型是
type alias Model =
{ currentUser : User
, users : [User]
}
您要的是
rotateUser : Model -> Model
rotateUser model =
let
nextUser = Maybe.withDefault
model.currentUser
(getNext model.users model.currentUser)
in
{ model | currentUser = nextUser }
getNext : List a -> a -> Maybe a
...
我们不执行getNext
,而是更改模型以简化生活:
type alias Model =
{ currentUser : User
, otherUsers : [User]
}
rotateUser : Model -> Model
rotateUser model =
case model.otherUsers of
[] -> model
(nextUser::rest) ->
{ model
| currentUser = nextUser
, otherUsers = rest ++ [model.currentUser]
}