Skip to content

Commit

Permalink
add Subset and SubsetCollection classes
Browse files Browse the repository at this point in the history
  • Loading branch information
n1crack committed Feb 6, 2024
1 parent 63a90b9 commit fb85558
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 69 deletions.
27 changes: 15 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ Here's a basic example of how to use the SubsetFinder package:

```php
use Ozdemir\SubsetFinder\SubsetFinder;
use Ozdemir\SubsetFinder\SubsetCollection;
use Ozdemir\SubsetFinder\Subset;

// Define your collection and subset criteria

Expand All @@ -28,15 +30,15 @@ $collection = collect([
// Add more items...
]);

$subsetCriteria = collect([
["quantity" => 5, "items" => [1, 2]],
["quantity" => 2, "items" => [3]],
$subsetCollection = new SubsetCollection([
Subset::of([1, 2])->take(5),
Subset::of([3])->take(2),
// Add more criteria...
]);


// Instantiate SubsetFinder
$subsetter = new SubsetFinder($collection, $subsetCriteria);
$subsetter = new SubsetFinder($collection, $subsetCollection);

// Optionally, configure sorting
$subsetter->sortBy('price');
Expand Down Expand Up @@ -74,10 +76,10 @@ $subSetQuantity = $subset->getSetQuantity()
### Prioritize items to be included in the subset
```php
// Seek subsets that meet the criteria
$subsetCriteria = collect([
["quantity" => 5, "items" => [1, 2, 3]], // Find a subset with a total quantity of 5 from items 1, 2, and 3 in the collection
["quantity" => 2, "items" => [4, 5]], // Find a subset with a total quantity of 2 from items 4 and 5 in the collection
["quantity" => 5, "items" => [12]], // Find a subset with a total quantity of 5 from item 12 in the collection
$subsetCollection = new SubsetCollection([
Subset::of([1, 2, 3])->take(5), // Find a subset with a total quantity of 5 from items 1, 2, and 3 in the collection
Subset::of([4, 5])->take(2), // Find a subset with a total quantity of 2 from items 4 and 5 in the collection
Subset::of([12])->take(5), // Find a subset with a total quantity of 5 from item 12 in the collection
// etc...
]);

Expand All @@ -91,18 +93,19 @@ $subsetter->sortBy('price');
```php
// We can use the fields with the defined names.
$subsetter->defineProps(
quantity: 'amount',
items: 'products',
id: 'name'
quantity: 'amount'
);

$collection = collect([
["name" => 1, "amount" => 11, "price" => 15],
// Add more items...
]);

// Find a subset with a total amount (quantity) of 5 from items named 1 and 2 (id) in the collection
$setCollection = collect([
["amount" => 5, "products" => [1, 2]],
// Add more sets...
Subset::of([1, 2])->take(5)
// define more...
]);
```

Expand Down
43 changes: 43 additions & 0 deletions src/Subset.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace Ozdemir\SubsetFinder;

class Subset
{
public array $items;
public int $quantity;

/**
* Subset constructor.
*
* @param array $items
* @param int $quantity
*/
public function __construct(array $items, int $quantity = 1)
{
$this->items = $items;
$this->quantity = $quantity;
}

/**
* Create a new instance of Subset with the given items.
*
* @param array $items
* @return self
*/
public static function of(array $items): self
{
return new static($items);
}

/**
* Create a new instance of Subset with the given items and quantity.
*
* @param int $quantity
* @return $this
*/
public function take(int $quantity): self
{
return new static($this->items, $quantity);
}
}
13 changes: 13 additions & 0 deletions src/SubsetCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Ozdemir\SubsetFinder;

use Illuminate\Support\Collection;


class SubsetCollection extends Collection
{

}


45 changes: 21 additions & 24 deletions src/SubsetFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,34 @@ class SubsetFinder
{
protected Collection $flatCollection;

private string $quantityFieldName = 'quantity';
private string $idFieldName = 'id';
private string $itemsFieldName = 'items';

private string $quantityFieldName = 'quantity';
private string $sortByField = 'id';
private bool $sortByDesc = false;

/**
* SubsetFinder constructor.
*
* @param Collection $collection
* @param Collection $subSetCriteria
* @param SubsetCollection $subsetCollection
*/
public function __construct(
public Collection $collection,
public Collection $subSetCriteria
public SubsetCollection $subsetCollection
) {
}

/**
* Define the field names for the quantity, items and id fields.
*
* @param string $quantity
* @param string $items
* @param string $id
* @return $this
*/
public function defineProps(string $quantity = 'quantity', string $items = 'items', string $id = 'id'): self
public function defineProps(string $id = 'id', string $quantity = 'quantity'): self
{
$this->quantityFieldName = $quantity;
$this->itemsFieldName = $items;
$this->idFieldName = $id;
$this->quantityFieldName = $quantity;

return $this;
}
Expand All @@ -66,24 +62,24 @@ public function sortBy($field, bool $descending = false): self
*/
public function getSetQuantity(): int
{
return $this->subSetCriteria
->map(fn ($setItem) => $this->calculateQuantityForSet($setItem))
return $this->subsetCollection
->map(fn ($subset) => $this->calculateQuantityForSet($subset))
->min();
}

/**
* Calculate the quantity for a given set item.
*
* @param array $setItem
* @param Subset $subset
* @return int
*/
protected function calculateQuantityForSet(array $setItem): int
protected function calculateQuantityForSet(Subset $subset): int
{
$quantity = $this->collection
->whereIn($this->idFieldName, $setItem[$this->itemsFieldName])
->whereIn($this->idFieldName, $subset->items)
->sum($this->quantityFieldName);

return (int)floor($quantity / $setItem[$this->quantityFieldName]);
return (int)floor($quantity / $subset->quantity);
}

/**
Expand All @@ -95,7 +91,7 @@ protected function getFlatCollection(): Collection
{
return $this->collection
->sortBy($this->sortByField, SORT_REGULAR, $this->sortByDesc)
->whereIn($this->idFieldName, $this->subSetCriteria->pluck($this->itemsFieldName)->flatten(1))
->whereIn($this->idFieldName, $this->subsetCollection->pluck('items')->flatten(1))
->flatMap(fn ($item) => $this->duplicateItemForQuantity($item));
}

Expand Down Expand Up @@ -138,18 +134,19 @@ public function get(): Collection
// Get the maximum quantity of sets that can be created from the collection
$maxSetQuantity = $this->getSetQuantity();

// Initialize a collection to store flattened items
$cartFlatten = collect();

// Flatten the collection
$this->flatCollection = $this->getFlatCollection();

// Initialize a collection to store flattened items
$cartFlatten = collect();

// Iterate over the subset criteria
foreach ($this->subSetCriteria as $subsetCriteria) {
foreach ($this->subsetCollection as $subset) {
// Filter and limit items based on subset criteria
$filteredItems = $this->filterAndLimit(
$subsetCriteria[$this->itemsFieldName],
$subsetCriteria[$this->quantityFieldName] * $maxSetQuantity
$subset->items,
$subset->quantity * $maxSetQuantity
);

// Add filtered items to the collection
Expand All @@ -172,10 +169,10 @@ public function get(): Collection
*/
protected function mapItemGroup(Collection $itemGroup): array
{
$setItem = $itemGroup->first();
$setItem[$this->quantityFieldName] = $itemGroup->count();
$item = $itemGroup->first();
$item[$this->quantityFieldName] = $itemGroup->count();

return [$setItem[$this->idFieldName] => $setItem];
return [$item[$this->idFieldName] => $item];
}

/**
Expand Down
Loading

0 comments on commit fb85558

Please sign in to comment.