Skip to content

Commit

Permalink
Add new class Set for simple Set-theoretical operations
Browse files Browse the repository at this point in the history
### Features

* Works only with primitive types int, float, string
* Implements set theortic operations union, intersection, complement
* Modifies set by adding, removing elements
* Implements \IteratorAggregate for use in loops

### Implementation details

Based on array functions:
* array_diff,
* array_merge,
* array_intersection,
* array_unique,
* array_values,
* sort.

### Drawbacks

* **Do not work with objects.**
* Power set and Cartesian product returning array of Set
  • Loading branch information
pflorek committed Sep 10, 2016
1 parent 90038be commit fa87eca
Show file tree
Hide file tree
Showing 3 changed files with 431 additions and 0 deletions.
127 changes: 127 additions & 0 deletions docs/math/set.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Set

Class that wraps PHP arrays containing primitive types to mathematical sets.

### Creation

To create Set use flat arrays containing primitives only:

```
use \Phpml\Math\Set;
$set = new Set([1, 2, 2, 3, 1.1, -1, -10]);
$set->toArray();
// return [-10, -1, 1, 1.1, 2, 3]
$set = new Set(['B', '', 'A']);
$set->toArray();
// return ['', 'A', 'B']
```

Injected array is sorted by SORT_ASC, duplicates are removed and index is rewritten.

### Union

Create the union of two Sets:

```
use \Phpml\Math\Set;
$union = Set::union(new Set([1, 3]), new Set([1, 2]));
$union->toArray();
//return [1, 2, 3]
```

### Intersection

Create the intersection of two Sets:

```
use \Phpml\Math\Set;
$intersection = Set::intersection(new Set(['A', 'C']), new Set(['B', 'C']));
$intersection->toArray();
//return ['C']
```

### Complement

Create the set-theoretic difference of two Sets:

```
use \Phpml\Math\Set;
$difference = Set::difference(new Set(['A', 'B', 'C']), new Set(['A']));
$union->toArray();
//return ['B', 'C']
```

### Adding elements

```
use \Phpml\Math\Set;
$set = new Set([1, 2]);
$set->addAll([3]);
$set->add(4);
$set->toArray();
//return [1, 2, 3, 4]
```

### Removing elements

```
use \Phpml\Math\Set;
$set = new Set([1, 2]);
$set->removeAll([2]);
$set->remove(1);
$set->toArray();
//return []
```

### Check membership

```
use \Phpml\Math\Set;
$set = new Set([1, 2]);
$set->containsAll([2, 3]);
//return false
$set->contains(1);
//return true
```

### Cardinality

```
use \Phpml\Math\Set;
$set = new Set([1, 2]);
$set->cardinality();
//return 2
```

### Is empty

```
use \Phpml\Math\Set;
$set = new Set();
$set->isEmpty();
//return true
```

### Working with loops

```
use \Phpml\Math\Set;
$set = new Set(['A', 'B', 'C']);
foreach($set as $element) {
echo "$element, ";
}
// echoes A, B, C
```
211 changes: 211 additions & 0 deletions src/Phpml/Math/Set.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
<?php

declare(strict_types=1);

namespace Phpml\Math;

class Set implements \IteratorAggregate
{
/**
* @var string[]|int[]|float[]
*/
private $elements;

/**
* @param string[]|int[]|float[] $elements
*/
public function __construct(array $elements = [])
{
$this->elements = self::sanitize($elements);
}

/**
* Creates the union of A and B.
*
* @param Set $a
* @param Set $b
*
* @return Set
*/
public static function union(Set $a, Set $b) : Set
{
return new self(array_merge($a->toArray(), $b->toArray()));
}

/**
* Creates the intersection of A and B.
*
* @param Set $a
* @param Set $b
*
* @return Set
*/
public static function intersection(Set $a, Set $b) : Set
{
return new self(array_intersect($a->toArray(), $b->toArray()));
}

/**
* Creates the difference of A and B.
*
* @param Set $a
* @param Set $b
*
* @return Set
*/
public static function difference(Set $a, Set $b) : Set
{
return new self(array_diff($a->toArray(), $b->toArray()));
}

/**
* Creates the Cartesian product of A and B.
*
* @param Set $a
* @param Set $b
*
* @return Set[]
*/
public static function cartesian(Set $a, Set $b) : array
{
$cartesian = [];

foreach ($a as $multiplier) {
foreach ($b as $multiplicand) {
$cartesian[] = new self(array_merge([$multiplicand], [$multiplier]));
}
}

return $cartesian;
}

/**
* Creates the power set of A.
*
* @param Set $a
*
* @return Set[]
*/
public static function power(Set $a) : array
{
$power = [new self()];

foreach ($a as $multiplicand) {
foreach ($power as $multiplier) {
$power[] = new self(array_merge([$multiplicand], $multiplier->toArray()));
}
}

return $power;
}

/**
* Removes duplicates and rewrites index.
*
* @param string[]|int[]|float[] $elements
*
* @return string[]|int[]|float[]
*/
private static function sanitize(array $elements) : array
{
sort($elements, SORT_ASC);

return array_values(array_unique($elements, SORT_ASC));
}

/**
* @param string|int|float $element
*
* @return Set
*/
public function add($element) : Set
{
return $this->addAll([$element]);
}

/**
* @param string[]|int[]|float[] $elements
*
* @return Set
*/
public function addAll(array $elements) : Set
{
$this->elements = self::sanitize(array_merge($this->elements, $elements));

return $this;
}

/**
* @param string|int|float $element
*
* @return Set
*/
public function remove($element) : Set
{
return $this->removeAll([$element]);
}

/**
* @param string[]|int[]|float[] $elements
*
* @return Set
*/
public function removeAll(array $elements) : Set
{
$this->elements = self::sanitize(array_diff($this->elements, $elements));

return $this;
}

/**
* @param string|int|float $element
*
* @return bool
*/
public function contains($element) : bool
{
return $this->containsAll([$element]);
}

/**
* @param string[]|int[]|float[] $elements
*
* @return bool
*/
public function containsAll(array $elements) : bool
{
return !array_diff($elements, $this->elements);
}

/**
* @return string[]|int[]|float[]
*/
public function toArray() : array
{
return $this->elements;
}

/**
* @return \ArrayIterator
*/
public function getIterator() : \ArrayIterator
{
return new \ArrayIterator($this->elements);
}

/**
* @return bool
*/
public function isEmpty() : bool
{
return $this->cardinality() == 0;
}

/**
* @return int
*/
public function cardinality() : int
{
return count($this->elements);
}
}
Loading

0 comments on commit fa87eca

Please sign in to comment.