-1

I have array and contains 50 values ,

example

[
    'london',
    'bluehit',
    'green',
    'lonpark',
    'abc',
    'aab',
    'lonsee',
]

I want to sort with preference given to values starting with a provided string, then traditional alphabetical sorting.

If I give an argument as lon then my array should be sorted as:

[
    'london',
    'lonpark',
    'lonsee',
    'aab',
    'abc',
    'blurhit',
    'green',
]
2
  • Is it an associative array? or multidimensional ? Commented Sep 24, 2010 at 12:36
  • 2
    Why is lonsee at the end of the sorted list, as well as at the beginning? Commented Sep 24, 2010 at 12:38

6 Answers 6

2
  1. replace the string in question with a character with code 1
  2. sort normally
  3. replace the character back

this is it ;)

 $str = "lon";
 $a = array('london', 'bluehit', 'green', 'lonpark', 'abc', 'aab', 'lonsee');
 $b = preg_replace("~^$str~", "\x01", $a);
 sort($b);
 $b = preg_replace('~\x01~', "lon", $b);
 print_r($b);

upd: even simpler is to prepend the string with "\x01" rather than replacing it. This also allows for case-insensitive matching or to match a set of strings:

 $str = "lon";
 $a = array('london', 'bluehit', 'green', 'Lonpark', 'abc', 'aab', 'lonsee');
 $b = preg_replace("~^$str~i", "\x01$0", $a);
 sort($b);
 $b = str_replace('~\x01~', "", $b);
 print_r($b);
0
2

As the others have said, usort and a bespoke comparator would fit well. Here's an example which has a factory function (in this case, a function which returns a function) which generates comparators (using closures) based on the required prefix.

$subject = explode(',', 'london,bluehit,green,lonpark,abc,aab,lonsee');

function make_comparator($prefix)
{
    return function ($a, $b) use ($prefix) {
        if (strpos($a, $prefix) === 0 && strpos($b, $prefix) !== 0) {
            // $a starts with $prefix (and $b does not), sift up
            return -1;
        } elseif (strpos($a, $prefix) !== 0 && strpos($b, $prefix) === 0) {
            // $b starts with $prefix (and $a does not), sift down
            return 1;
        } else {
            // Otherwise, do a normal string comparison
            return strcmp($a, $b);
        }
    };
}

$sorted = $subject;
usort($sorted, make_comparator('lon'));
var_dump($sorted);

For PHP versions less than 5.3.0 (required for above) you could do something similar:

function prefix_comparator($a, $b, $prefix) {
    if (strpos($a, $prefix) === 0 && strpos($b, $prefix) !== 0) {
        // $a starts with $prefix (and $b does not), sift up
        return -1;
    } elseif (strpos($a, $prefix) !== 0 && strpos($b, $prefix) === 0) {
        // $b starts with $prefix (and $a does not), sift down
        return 1;
    } else {
        // Otherwise, do a normal string comparison
        return strcmp($a, $b);
    }
}

$sort_by_lon = create_function('$a, $b', 'return prefix_comparator($a, $b, "lon");');
$sorted = $subject;
usort($sorted, $sort_by_lon);
var_dump($sorted);

(Apologies for the jargon)

4
  • Hi, salathe , thanks, is there any function call use , bcoz in the above function u used the use keyword, Commented Sep 24, 2010 at 12:59
  • Bharanikumar, the use keyword is used to allow an anonymous function access to variables outside of its normal scope (i.e. the closure). Commented Sep 24, 2010 at 13:06
  • i executed the above code , i got parse error on this line return function ($a, $b) use ($prefix), program not allowing me to execute.. getting error Commented Sep 24, 2010 at 13:09
  • You're not using PHP 5.3.0 (or newer). The documentation that I pointed you to should have made is clear that version was a requirement. See my edit for older/lower versions of PHP which cannot use closures. Commented Sep 24, 2010 at 13:55
1

This gets asked a lot. Take a look at using a custom sorting function. From php.net: uksort and usort.

3
  • 5
    Hehe. Kinda fun to think of using a function named uksort() to put London at the top of the list. ;-) Commented Sep 24, 2010 at 12:40
  • Haha haha haha ha! (I would have just typed lol but I was foiled by the character limit.) Commented Sep 24, 2010 at 14:03
  • This hint to read the manual would have been better as a comment under the question. Commented Oct 25, 2023 at 4:18
1

You can use usort, you can define your own function for sorting the data.

0

Here's another possibility for ver. 5.3+:

function pref_sort($arr, $pref, $case_insensitive = true)
{
    $case_insensitive ? natcasesort($arr) : sort($arr);        
    $pref_arr = array_filter($arr, 
        function($val) use ($pref){
            return (strpos(strtolower($val), strtolower($pref)) === 0);
        });
    return array_values($pref_arr + array_diff($arr, $pref_arr));
}

Usage:

$pref_str = 'lon';
$array = array('green', 'Lonpark', 'london', 'bluehit', 'abc', 
               'aab', 'lonsee', 'lon', 'Lon', 'Aab');

// Case-insensitive:
$sorted_array = pref_sort($array, $pref_str);
print_r($sorted_array);
/**
Array
(
    [0] => lon
    [1] => Lon
    [2] => london
    [3] => Lonpark
    [4] => lonsee
    [5] => Aab
    [6] => aab
    [7] => abc
    [8] => bluehit
    [9] => green
)
**/ 

// Case-sensitive:
$sorted_array = pref_sort($array, $pref_str, false);
print_r($sorted_array);
/**
Array
(
    [0] => Lon
    [1] => Lonpark
    [2] => lon
    [3] => london
    [4] => lonsee
    [5] => Aab
    [6] => aab
    [7] => abc
    [8] => bluehit
    [9] => green
)
**/
0

To perform fewest iterated function calls, use array_multisort().

Loop once to populate an array of boolean values indicating if the needle string was found at the start of each string. When sorting boolean values in an ascending direction, false comes before true.

Then break ties by comparing whole strings.

Code: (Demo)

$startsWith = 'lon';

array_multisort(
    array_map(
        fn($w) => !str_starts_with($w, $startsWith),
        $array
    ),
    $array
);
var_export($array);

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.