Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[stdlib] Add List.map(fn(mut T)->None) #3839

Open
wants to merge 1 commit into
base: nightly
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions stdlib/src/collections/list.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,35 @@ struct List[T: CollectionElement, hint_trivial_type: Bool = False](
"""
return self.data

fn map(ref self, func: fn (mut T) -> None) -> Self:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought: The API you're describing seems more like for_each than map.
fn(mut T) -> None is a common for_each signature, whereas map tends to be fn[U: CollectionElement](T) -> U.

Examples:

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I think it was just a mistake in assuming the output will be the same type as the input collection type

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not exactly. for_each tends to mutate in place, while map tends to create a new allocation. Users associate both APIs with those characteristics in my opinion.

Copy link
Contributor

@martinvuyk martinvuyk Dec 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant that I think the OP meant map as in map a func to return a new instance with copied values changed, just that he forgot the use case where the collection type of the result might be different.

personal note: I'd actually like us to call for_each apply because it's a name used in the pandas and numpy ecosystem and is IMO much more intuitive (see PR #3877)

"""Map the values of the list into a new list trough a function.

Args:
func: The function used on every elements to create the new list.

Returns:
A new `List` created by calling `func` on every elements of `self`.

For example:
```mojo
fn MyFunc(mut e: Int):
e+=1

var MyList = List(0, 1, 2).map(MyFunc)

print(
MyList[0] == 1,
MyList[1] == 2,
MyList[2] == 3,
)
```.

"""
var tmp = self
for i in tmp:
func(i[])
return tmp


fn _clip(value: Int, start: Int, end: Int) -> Int:
return max(start, min(value, end))
Expand Down
16 changes: 16 additions & 0 deletions stdlib/test/collections/test_list.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -924,6 +924,21 @@ def test_list_repr():
assert_equal(empty.__repr__(), "[]")


def test_list_map():
fn MyFunc(mut e: Int):
e += 1

var lst = List(0, 1, 2).map(MyFunc)
for e in range(len(lst)):
assert_equal(lst[e], e + 1)

lst = List(0, 1, 2)
var lst2 = lst.map(MyFunc)
for e in range(len(lst)):
assert_equal(lst[e], e)
assert_equal(lst2[e], e + 1)


# ===-------------------------------------------------------------------===#
# main
# ===-------------------------------------------------------------------===#
Expand Down Expand Up @@ -962,3 +977,4 @@ def main():
test_indexing()
test_list_dtor()
test_list_repr()
test_list_map()
Loading