Completed
Push — data_structures ( b3e6cb )
by Doug
18:44
created

PackedBoxList::compare()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 11
Code Lines 7

Duplication

Lines 11
Ratio 100 %

Importance

Changes 0
Metric Value
dl 11
loc 11
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 7
nc 4
nop 2
1
<?php
2
/**
3
 * Box packing (3D bin packing, knapsack problem)
4
 * @package BoxPacker
5
 * @author Doug Wright
6
 */
7
declare(strict_types=1);
8
namespace DVDoug\BoxPacker;
9
10
use ArrayIterator, Countable, IteratorAggregate, Traversable;
11
use function reset;
12
13
/**
14
 * List of packed boxes
15
 * @author Doug Wright
16
 * @package BoxPacker
17
 */
18
class PackedBoxList implements IteratorAggregate
19
{
20
    /**
21
     * Average (mean) weight of boxes
22
     * @var float
23
     */
24
    protected $meanWeight;
25
26
    /**
27
     * List containing boxes
28
     * @var Box[]
29
     */
30
    private $list = [];
31
32
    /**
33
     * Has this list already been sorted?
34
     * @var bool
35
     */
36
    private $isSorted = false;
37
38
    /**
39
     * @return Traversable
40
     */
41 View Code Duplication
    public function getIterator(): Traversable
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
42
    {
43
        if (!$this->isSorted) {
44
            usort($this->list, [$this, 'compare']);
45
            $this->isSorted = true;
46
        }
47
        return new ArrayIterator($this->list);
48
    }
49
50
    /**
51
     * Number of items in list
52
     * @return int
53
     */
54
    public function count(): int
55
    {
56
        return count($this->list);
57
    }
58
59
    /**
60
     * @param PackedBox $item
61
     */
62
    public function insert(PackedBox $item)
63
    {
64
        $this->list[] = $item;
65
    }
66
67
    /**
68
     * Do a bulk insert
69
     * @param PackedBox[] $boxes
70
     */
71
    public function insertFromArray(array $boxes): void
72
    {
73
        foreach ($boxes as $box) {
74
            $this->insert($box);
75
        }
76
    }
77
78 View Code Duplication
    public function top(): PackedBox
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
79
    {
80
        if (!$this->isSorted) {
81
            usort($this->list, [$this, 'compare']);
82
            $this->isSorted = true;
83
        }
84
        return reset($this->list);
85
    }
86
87
    /**
88
     * @param PackedBox $boxA
89
     * @param PackedBox $boxB
90
     *
91
     * @return int
92
     */
93 View Code Duplication
    private function compare(PackedBox $boxA, PackedBox $boxB): int
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
94
    {
95
        $choice = $boxB->getItems()->count() <=> $boxA->getItems()->count();
96
        if ($choice === 0) {
97
            $choice = $boxB->getInnerVolume() <=> $boxA->getInnerVolume();
98
        }
99
        if ($choice === 0) {
100
            $choice = $boxA->getWeight() <=> $boxB->getWeight();
101
        }
102
        return $choice;
103
    }
104
105
    /**
106
     * Calculate the average (mean) weight of the boxes
107
     * @return float
108
     */
109
    public function getMeanWeight(): float
110
    {
111
        if (!is_null($this->meanWeight)) {
112
            return $this->meanWeight;
113
        }
114
115
        /** @var PackedBox $box */
116
        foreach ($this->list as $box) {
117
            $this->meanWeight += $box->getWeight();
0 ignored issues
show
Bug introduced by
The method getWeight() does not seem to exist on object<DVDoug\BoxPacker\Box>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
118
        }
119
120
        return $this->meanWeight /= count($this->list);
121
    }
122
123
    /**
124
     * Calculate the variance in weight between these boxes
125
     * @return float
126
     */
127
    public function getWeightVariance(): float
128
    {
129
        $mean = $this->getMeanWeight();
130
131
        $weightVariance = 0;
132
        /** @var PackedBox $box */
133
        foreach ($this->list as $box) {
134
            $weightVariance += ($box->getWeight() - $mean) ** 2;
135
        }
136
137
        return round($weightVariance / count($this->list), 1);
138
    }
139
140
    /**
141
     * Get volume utilisation of the set of packed boxes
142
     * @return float
143
     */
144
    public function getVolumeUtilisation(): float
145
    {
146
        $itemVolume = 0;
147
        $boxVolume = 0;
148
149
        /** @var PackedBox $box */
150
        foreach ($this as $box) {
151
            $boxVolume += $box->getInnerVolume();
152
153
            /** @var PackedItem $item */
154
            foreach ($box->getItems() as $item) {
155
                $itemVolume += ($item->getItem()->getWidth() * $item->getItem()->getLength() * $item->getItem()->getDepth());
156
            }
157
        }
158
159
        return round($itemVolume / $boxVolume * 100, 1);
160
    }
161
162
}
163