1

I have an array with string indices, that I need partially sorted. That is, some elements must be moved first, but the others should remain untouched in their current (PHP-internal) order:

# The element with key "c" should be first
$foo = array(
    "a" => 1,
    "b" => 2,
    "c" => 3,
    "d" => 4,
);

uksort($foo, function ($a, $b) {
    if ($a === "c") {
        return -1;
    } elseif ($b === "c") {
        return 1;
    }
    return 0;
});

var_dump($foo);

What I expected:

array(4) { ["c"]=> int(3) ["a"]=> int(1) ["b"]=> int(2) ["d"]=> int(4) }
//--------------------------^ "a" remains first of the unsorted ones

What I got:

array(4) { ["c"]=> int(3) ["d"]=> int(4) ["b"]=> int(2) ["a"]=> int(1) }
//--------------------------^ "d" moved above "a"

This seems due to the sorting algorithm uksort() uses internally, which destroys the fragile order of elements. Is there any other way to achieve this sorting?

6
  • What part of the array do you actually need sorted? Commented Apr 29, 2013 at 16:52
  • I need an array, that, when put in a foreach loop, provides the keys in the order "c", "a", "b", "d". I have an array, that has the keys such, that the order is "a", "b", "c", "d". From that I need to get to the above one. Commented Apr 29, 2013 at 16:57
  • I meant what's the logic? You want to move the specific element to the top? You want to move the 3rd element to the top? What do you want when the array is of different length? Commented Apr 29, 2013 at 16:59
  • Actually, I want elements with the key "c" to be placed first. Use case is a special CSS serialization. I need keys named "@charset" to be first, keys named "@import" to be second, and all others (arbitrarily many) should remain in their position. Commented Apr 29, 2013 at 17:01
  • Maybe I'm not interpreting this correctly, but you could have at most one "@charset" key and one "@import" key, so you'll be moving 2 elements at the most? Commented Apr 29, 2013 at 17:03

2 Answers 2

1

Using any sort function is overkill for this task. You merely need to merge the input array into a lone array containing the element which should come first. The array union operator (+) will do nicely for your associative array (otherwise array_merge() will do).

Codes: (Demos)

if key c is guaranteed to exist:

$foo = array(
    "a" => 1,
    "b" => 2,
    "c" => 3,
    "d" => 4,
);
$foo = ['c' => $foo['c']] + $foo;
var_export($foo);

if key c might not exist check for it first:

$bar = array(
    "a" => 1,
    "b" => 2,
    "d" => 4,
);
if (array_key_exists('c', $bar)) {
    $bar = ['c' => $bar['c']] + $bar;
}
var_export($bar);

Output:

array (
  'c' => 3,
  'a' => 1,
  'b' => 2,
  'd' => 4,
)

and

array (
  'a' => 1,
  'b' => 2,
  'd' => 4,
)
Sign up to request clarification or add additional context in comments.

Comments

0

This worked for me and returned:

array(4) { ["c"]=> int(3) ["a"]=> int(1) ["b"]=> int(2) ["d"]=> int(4) }

<?php 

# The element with key "c" should be first
$foo = array(
    "a" => 1,
    "b" => 2,
    "c" => 3,
    "d" => 4,
);

uksort($foo, function ($a, $b) {
    if ($a === "c") {
        return -1;
    } else
        return 1;
});

var_dump($foo);

?>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.