Đinh Carabus
Đinh Carabus

Reputation: 3496

Move some items to the end of the array if they fulfill a specific condition

I have an array of paths that I would like to sort ...

Array
(
    /something/foo1
    /something/special/foo2
    /something/foo3
    /something/special/foo4
    /something/foo5
    /something/special/foo6
)

... so that all paths that contain /special/ end up at the end of the array like this:

Array
(
    /something/foo1
    /something/foo3
    /something/foo5
    /something/special/foo2
    /something/special/foo4
    /something/special/foo6
)

The original sort order of paths must remain the same (so 1,2,3,4,5,6 => 1,3,5,2,4,6). Is there an elegant way to do this? Can this be implemented by using the usort function?

Upvotes: 0

Views: 1033

Answers (2)

Andras
Andras

Reputation: 3055

you can use unset and append [], like so

$x = array(1,2,3);
$x[] = $x[1];
unset($x[1]);
print_r($x);

Array
(
    [0] => 1
    [2] => 3
    [3] => 2
)

You can thus loop over the array, test each element, and flip to the end the ones that contain the pattern.

$len = count($a);
for ($i=0; $i<$len; $i++) {
    if (...) {
        $a[] = $a[i];
        unset($a[i]);
    }
}

Edit: php's arrays are lists, hashes and arrays simultaneously. It is possible to move an element to the end while retaining its index! For example

$a = array(1,2,3);

$t = $a[1];
unset($a[1]);
$a[1] = $t;

print_r($a);
Array
(
    [0] => 1
    [2] => 3
    [1] => 2
)

Upvotes: 1

rjdown
rjdown

Reputation: 9227

In your specific example, you can simply use asort($array);

But that is assuming foo is always foo.

Output:

array(6) {
  [0]=>
  string(15) "/something/foo1"
  [2]=>
  string(15) "/something/foo3"
  [4]=>
  string(15) "/something/foo5"
  [1]=>
  string(23) "/something/special/foo2"
  [3]=>
  string(23) "/something/special/foo4"
  [5]=>
  string(23) "/something/special/foo6"
}

If that's not the case, let me know and I'll do something else

... here is new method ref comment:

$array  = array(
    '/something/zoo',
    '/something/special/foo',
    '/something/loo',
    '/something/special/goo',
    '/something/boo',
    '/something/special/poo'
);
uasort($array, function($a, $b) {
    $specialInA = strpos($a, '/special/') !== false;
    $specialInB = strpos($b, '/special/') !== false;
    if ($specialInA > $specialInB) {
        return 1;
    }
    if ($specialInB > $specialInA) {
        return -1;
    }
    return $a > $b;
});

Output:

array(6) {
  [4]=>
  string(14) "/something/boo"
  [2]=>
  string(14) "/something/loo"
  [0]=>
  string(14) "/something/zoo"
  [1]=>
  string(22) "/something/special/foo"
  [3]=>
  string(22) "/something/special/goo"
  [5]=>
  string(22) "/something/special/poo"
}

Can probably be written better but should work

Upvotes: 2

Related Questions