diff --git a/README.md b/README.md
index 3f8208e..4ac967c 100644
--- a/README.md
+++ b/README.md
@@ -26,9 +26,12 @@ Collection is a set of useful wrapper classes for arrays, similar to Java's or K
1. [Getting started](#maps-getting-started)
2. [Access elements](#maps-access-elements)
3. [Manipulate](#maps-manipulate)
-5. [Stack](#stack)
-6. [Queue](#queue)
-7. [Contribution](#contribution)
+ 4. [Map elements](#maps-map)
+ 5. [Filter map entries](#maps-filter)
+5. [Combining Lists and Maps](#lists-maps)
+6. [Stack](#stack)
+7. [Queue](#queue)
+8. [Contribution](#contribution)
@@ -552,8 +555,246 @@ Seboettg\Collection\Lists\ListInterface@anonymous Object
### Manipulate a map
+```php
+use function Seboettg\Collection\Map\emptyMap;
+
+$map = emptyMap();
+
+//put
+$map->put("ABC", 1);
+echo $map["ABC"]; // 1
+
+//put via array assignment
+$map["ABC"] = 2;
+echo $map["ABC"]; // 2
+
+//remove
+$map->put("DEF", 3);
+$map->remove("DEF");
+echo $map->get("DEF"); // null
+```
+
+
+
+### Map elements
+
+The signature of given transform function for mapping must have either a `Pair` parameter or a `key` and a `value` parameter.
+The map function always returns a list of type `ListInterface`:
+
+```php
+use function Seboettg\Collection\Map\mapOf;
+
+class Asteroid {
+ public string $name;
+ public ?string $explorer;
+ public ?float $diameter;
+ public function __construct(string $name, string $explorer, float $diameter = null)
+ {
+ $this->name = $name;
+ $this->explorer = $explorer;
+ $this->diameter = $diameter;
+ }
+}
+
+$asteroids = $asteroidExplorerMap
+ ->map(fn (Pair $pair): Asteroid => new Asteroid($pair->getKey(), $pair->getValue()));
+
+print_r($asteroids);
+```
+output
+```
+Seboettg\Collection\Lists\ListInterface@anonymous Object
+(
+ [array:Seboettg\Collection\Lists\ListInterface@anonymous:private] => Array
+ (
+ [0] => Asteroid Object
+ (
+ [name] => Ceres
+ [explorer] => Giuseppe Piazzi
+ [diameter] =>
+ )
+
+ [1] => Asteroid Object
+ (
+ [name] => Pallas
+ [explorer] => Heinrich Wilhelm Olbers
+ [diameter] =>
+ )
+
+ [2] => Asteroid Object
+ (
+ [name] => Juno
+ [explorer] => Karl Ludwig Harding
+ [diameter] =>
+ )
+
+ [3] => Asteroid Object
+ (
+ [name] => Vesta
+ [explorer] => Heinrich Wilhelm Olbers
+ [diameter] =>
+ )
+
+ )
+
+ [offset:Seboettg\Collection\Lists\ListInterface@anonymous:private] => 0
+)
+```
+You get the same result with a key-value signature:
+```php
+$asteroids = $asteroidExplorerMap
+ ->map(fn (string $key, string $value): Asteroid => new Asteroid($key, $value));
+```
+
+
+
+### Filter entries of a map
+
+You may filter for elements by this way:
+
+```php
+$asteroidExplorerMap->filter(fn (Pair $pair): bool => $pair->getKey() !== "Juno");
+```
+or by this way:
+```php
+$asteroidExplorerMap->filter(fn (string $key, string $value): bool => $key !== "Juno");
+```
+
+
+
+### Combining Lists and Maps
+
+There are a lot of opportunities to use lists and maps in real world scenarios with a lot of
+advantages e.g. less boilerplate code and better code readability.
+
+The following json file represents a customer file that we want to use processing.
+
+_customer.json_
+```json
+[
+ {
+ "id": "A001",
+ "lastname": "Doe",
+ "firstname": "John",
+ "createDate": "2022-06-10 09:21:12"
+ },
+ {
+ "id": "A002",
+ "lastname": "Doe",
+ "firstname": "Jane",
+ "createDate": "2022-06-10 09:21:13"
+ },
+ {
+ "id": "A004",
+ "lastname": "Mustermann",
+ "firstname": "Erika",
+ "createDate": "2022-06-11 08:21:13"
+ }
+]
+```
+We would like to get a map that associates the customer id with respective objects of type `Customer` and we want to apply a filter
+so that we get only customers with lastname Doe.
+
+```php
+use function Seboettg\Collection\Lists\listFromArray;
+
+class Customer {
+ public string $id;
+ public string $lastname;
+ public string $firstname;
+ public DateTime $createDate;
+ public function __construct(
+ string $id,
+ string $lastname,
+ string $firstname,
+ DateTime $createDate
+ ) {
+ $this->id = $id;
+ $this->lastname = $lastname;
+ $this->firstname = $firstname;
+ $this->createDate = $createDate;
+ }
+}
+
+$customerList = listFromArray(json_decode(file_get_contents("customer.json"), true));
+$customerMap = $customerList
+ ->filter(fn (array $customerArray) => $customerArray["lastname"] === "Doe") // filter for lastname Doe
+ ->map(fn (array $customerArray) => new Customer(
+ $customerArray["id"],
+ $customerArray["lastname"],
+ $customerArray["firstname"],
+ DateTime::createFromFormat("Y-m-d H:i:s", $customerArray["createDate"])
+ )) // map array to customer object
+ ->associateBy(fn(Customer $customer) => $customer->id); // link the id with the respective customer object
+print_($customerMap);
+```
+output
+```
+Seboettg\Collection\Map\MapInterface@anonymous Object
+(
+ [array:Seboettg\Collection\Map\MapInterface@anonymous:private] => Array
+ (
+ [A001] => Customer Object
+ (
+ [id] => A001
+ [lastname] => Doe
+ [firstname] => John
+ [createDate] => DateTime Object
+ (
+ [date] => 2022-06-10 09:21:12.000000
+ [timezone_type] => 3
+ [timezone] => UTC
+ )
+ )
+ [A002] => Customer Object
+ (
+ [id] => A002
+ [lastname] => Doe
+ [firstname] => Jane
+ [createDate] => DateTime Object
+ (
+ [date] => 2022-06-10 09:21:13.000000
+ [timezone_type] => 3
+ [timezone] => UTC
+ )
+ )
+ )
+)
+```
+
+Another example: Assuming we have a customer service with a `getCustomerById` method.
+We have a list of IDs with which we want to request the service.
+
+```php
+$listOfIds = listOf("A001", "A002", "A004");
+$customerMap = $listOfIds
+ ->associateWith(fn ($customerId) => $customerService->getById($customerId))
+```
+output
+```
+Seboettg\Collection\Map\MapInterface@anonymous Object
+(
+ [array:Seboettg\Collection\Map\MapInterface@anonymous:private] => Array
+ (
+ [A001] => Customer Object
+ (
+ [id] => A001
+ [lastname] => Doe
+ [firstname] => John
+ [createDate] => DateTime Object
+ (
+ [date] => 2022-06-10 09:21:12.000000
+ [timezone_type] => 3
+ [timezone] => UTC
+ )
+ )
+ [A002] ...
+ [A004] ...
+ )
+)
+```
## Stack ##
diff --git a/src/Map/MapTrait.php b/src/Map/MapTrait.php
index 2fe95af..fea36f5 100644
--- a/src/Map/MapTrait.php
+++ b/src/Map/MapTrait.php
@@ -264,8 +264,23 @@ public function getOrElse($key, callable $default)
public function map(callable $transform): ListInterface
{
$list = emptyList();
- foreach ($this->array as $key => $value) {
- $list->add($transform(pair($key, $value)));
+ try {
+ $reflected = new ReflectionFunction($transform);
+ if (count($reflected->getParameters()) === 1) {
+ assertValidCallable($transform, [Pair::class]);
+ foreach ($this->array as $key => $value) {
+ $list->add($transform(pair($key, $value)));
+ }
+ } else {
+ if (count($reflected->getParameters()) === 2) {
+ assertValidCallable($transform, ["scalar", "mixed"]);
+ }
+ foreach ($this->array as $key => $value) {
+ $list->add($transform($key, $value));
+ }
+ }
+ } catch (ReflectionException $ex) {
+ throw new NotApplicableCallableException("Invalid callable passed.");
}
return $list;
}
diff --git a/tests/ArrayListTest.php b/tests/ArrayListTest.php
index 6f976a0..bede225 100644
--- a/tests/ArrayListTest.php
+++ b/tests/ArrayListTest.php
@@ -364,7 +364,7 @@ public function testAssociateWith()
$map = [
"A001" => \Seboettg\Collection\Test\stdclass(["id" => "A001", "lastname" => "Doe", "firstname" => "John", "createDate" => DateTime::createFromFormat("Y-m-d H:i:s", "2022-06-10 09:21:12")]),
"A002" => \Seboettg\Collection\Test\stdclass(["id" => "A002", "lastname" => "Doe", "firstname" => "Jane", "createDate" => DateTime::createFromFormat("Y-m-d H:i:s", "2022-06-10 09:21:13")]),
- "A004" => \Seboettg\Collection\Test\stdclass(["id" => "A002", "lastname" => "Mustermann", "firstname" => "Erika", "createDate" => DateTime::createFromFormat("Y-m-d H:i:s", "2022-06-11 08:21:13")]),
+ "A004" => \Seboettg\Collection\Test\stdclass(["id" => "A004", "lastname" => "Mustermann", "firstname" => "Erika", "createDate" => DateTime::createFromFormat("Y-m-d H:i:s", "2022-06-11 08:21:13")]),
];
$customerRepository = $this->getMockBuilder(CustomerRepository::class)
@@ -375,9 +375,9 @@ public function testAssociateWith()
->method("getById")
->willReturnCallback(fn($id) => $map[$id]);
- $customerMap = $listOfIds->associateWith(function ($customerId) use ($customerRepository) {
- return $customerRepository->getById($customerId);
- });
+ $customerMap = $listOfIds->associateWith(fn ($customerId) =>
+ $customerRepository->getById($customerId)
+ );
$this->assertEquals(
mapOf(