Skip to content

Commit 551e51e

Browse files
authored
Heavily optimize SnakList::moveSnaksToBottom (#762)
1 parent 639f9c5 commit 551e51e

2 files changed

Lines changed: 48 additions & 36 deletions

File tree

src/Snak/SnakList.php

Lines changed: 16 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -158,53 +158,33 @@ public function getHash() {
158158
}
159159

160160
/**
161-
* Orders the snaks in the list grouping them by property.
161+
* Groups snaks by property, and optionally orders them.
162162
*
163-
* @param string[] $order List of serliazed property ids to order by.
163+
* @param string[] $order List of property ID strings to order by. Snaks with other properties
164+
* will also be grouped, but put at the end, in the order each property appeared first in the
165+
* original list.
164166
*
165167
* @since 0.5
166168
*/
167169
public function orderByProperty( array $order = [] ) {
168-
$snaksByProperty = $this->getSnaksByProperty();
169-
$orderedProperties = array_unique( array_merge( $order, array_keys( $snaksByProperty ) ) );
170-
171-
foreach ( $orderedProperties as $property ) {
172-
if ( array_key_exists( $property, $snaksByProperty ) ) {
173-
$snaks = $snaksByProperty[$property];
174-
$this->moveSnaksToBottom( $snaks );
175-
}
170+
$byProperty = array_fill_keys( $order, [] );
171+
172+
/** @var Snak $snak */
173+
foreach ( $this as $snak ) {
174+
$byProperty[$snak->getPropertyId()->getSerialization()][] = $snak;
176175
}
177-
}
178176

179-
/**
180-
* @param Snak[] $snaks to remove and re add
181-
*/
182-
private function moveSnaksToBottom( array $snaks ) {
183-
foreach ( $snaks as $snak ) {
184-
$this->removeSnak( $snak );
185-
$this->addSnak( $snak );
177+
$ordered = [];
178+
foreach ( $byProperty as $snaks ) {
179+
$ordered = array_merge( $ordered, $snaks );
186180
}
187-
}
188181

189-
/**
190-
* Gets the snaks in the current object in an array
191-
* grouped by property id
192-
*
193-
* @return array[]
194-
*/
195-
private function getSnaksByProperty() {
196-
$snaksByProperty = [];
182+
$this->exchangeArray( $ordered );
197183

198-
foreach ( $this as $snak ) {
199-
/** @var Snak $snak */
200-
$propertyId = $snak->getPropertyId()->getSerialization();
201-
if ( !isset( $snaksByProperty[$propertyId] ) ) {
202-
$snaksByProperty[$propertyId] = [];
203-
}
204-
$snaksByProperty[$propertyId][] = $snak;
184+
$index = 0;
185+
foreach ( $ordered as $snak ) {
186+
$this->offsetHashes[$snak->getHash()] = $index++;
205187
}
206-
207-
return $snaksByProperty;
208188
}
209189

210190
/**

tests/unit/Snak/SnakListTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ public function orderByPropertyProvider() {
165165
$id1 = new PropertyId( 'P1' );
166166
$id2 = new PropertyId( 'P2' );
167167
$id3 = new PropertyId( 'P3' );
168+
$id4 = new PropertyId( 'P4' );
168169

169170
/**
170171
* List of test data containing snaks to initialize SnakList objects. The first list of
@@ -238,6 +239,27 @@ public function orderByPropertyProvider() {
238239
],
239240
[ 'P1' ]
240241
],
242+
'Multiple IDs in order' => [
243+
[
244+
new PropertyValueSnak( $id1, new StringValue( 'a' ) ),
245+
new PropertyValueSnak( $id2, new StringValue( 'b' ) ),
246+
new PropertyValueSnak( $id1, new StringValue( 'c' ) ),
247+
new PropertyValueSnak( $id3, new StringValue( 'd' ) ),
248+
new PropertyValueSnak( $id4, new StringValue( 'e' ) ),
249+
new PropertyValueSnak( $id2, new StringValue( 'f' ) ),
250+
new PropertyValueSnak( $id4, new StringValue( 'g' ) ),
251+
],
252+
[
253+
new PropertyValueSnak( $id2, new StringValue( 'b' ) ),
254+
new PropertyValueSnak( $id2, new StringValue( 'f' ) ),
255+
new PropertyValueSnak( $id3, new StringValue( 'd' ) ),
256+
new PropertyValueSnak( $id1, new StringValue( 'a' ) ),
257+
new PropertyValueSnak( $id1, new StringValue( 'c' ) ),
258+
new PropertyValueSnak( $id4, new StringValue( 'e' ) ),
259+
new PropertyValueSnak( $id4, new StringValue( 'g' ) ),
260+
],
261+
[ 'P2', 'P3', 'P1' ]
262+
],
241263
];
242264

243265
$arguments = [];
@@ -272,6 +294,16 @@ public function testOrderByProperty( SnakList $snakList, SnakList $expected, arr
272294
} else {
273295
$this->assertNotSame( $initialSnakList->getHash(), $snakList->getHash() );
274296
}
297+
298+
/** @var Snak $snak */
299+
foreach ( $snakList as $snak ) {
300+
$hash = $snak->getHash();
301+
$this->assertSame(
302+
$hash,
303+
$snakList->getSnak( $hash )->getHash(),
304+
'Reordering must not mess up the lists internal state'
305+
);
306+
}
275307
}
276308

277309
public function testComparableInterface() {

0 commit comments

Comments
 (0)