Sort array string-type keys by a custom alphabet?
Asked Answered
L

5

6

I want to sort arrays by key in php, but the alphabet that I'm using is not the normal English alphabet -- it's a self-created alphabet. Is this possible?

My alphabet is:

$alphabet = "AjawbpfmnrhHxXsSqkgtTdD =";

The array is like this:

Array (
   [=k_0] => Array(
       [0] => DI.3,2 &dwA-nTr& @Hrw@
       [1] => mA
       [2] => =k
       [3] => Sfj,t
       [4] => =k
       [5] => pXr
       )
   [aA_2] => Array(
       [0] => DI.7,4 &dwA-nTr& @Hrw-smA-tA,wj@
       [1] => snD
       [2] => aA
       [3] => Sfj,t
       [4] => jt
       [5] => jt,w
       )
  [sqA_1] => Array(
       [0] => DI.6,18 &dwA-nTr& @nswt@
       [1] => ra
       [2] => sqA
       [3] => Sfj,t
       [4] => =s
       [5] => r
       )
   );

So if I sort this array following my alphabet then the array with the key [=k_0] should be at the end.

Lorileelorilyn answered 14/6, 2011 at 21:44 Comment(4)
What do you mean by self created alphabet? How do you map those? don't you still need an integer to represent it?Fenestella
any example of such keys, maybe?Laddie
the alphabet is $alphabet = "AjawbpfmnrhHxXsSqkgtTdD"Lorileelorilyn
the alphabet is $alphabet = "AjawbpfmnrhHxXsSqkgtTdD ="; the array is like this: Array ([=k_0] => Array([0] => DI.3,2 &dwA-nTr& @Hrw@ [1] => mA [2] => =k [3] => Sfj,t [4] => =k [5] => pXr ) [aA_2] => Array( [0] => DI.7,4 &dwA-nTr& @Hrw-smA-tA,wj@ [1] => snD [2] => aA [3] => Sfj,t [4] => jt [5] => jt,w ) [sqA_1] => Array( [0] => DI.6,18 &dwA-nTr& @nswt@ [1] => ra [2] => sqA [3] => Sfj,t [4] => =s [5] => r ) ); so if i sort this array following my alphabet the array with the key [=k_0] should be at the end.Lorileelorilyn
S
7

You can use the usort() function and provide your own sorting logic.

See php.net for an example.

Edit: use uksort, not usort. See http://www.php.net/manual/en/function.uksort.php. Thanks @Darien!

A slightly modified example from php.net - the original code with an $alphabet mapping added:

function cmp($a, $b)
{
    // custom sort order - just swapps 2 and 3.
    $alphabet = array (1 => 1, 2 => 3, 3 => 2, 4 => 4, 5 => 5, 6=> 6);

    if ($alphabet[$a] == $alphabet[$b]) {
        return 0;
    }
    return ($alphabet[$a] < $alphabet[$b]) ? -1 : 1;
}

$a = array(3 => 'c' , 2 => 'b', 5 => 'e', 6 => 'f', 1=>'a');
uksort($a, "cmp");

foreach ($a as $key => $value) {
    echo "$key: $value\n";
}
Softhearted answered 14/6, 2011 at 21:50 Comment(7)
Yes - OP has custom requirements not directly covered by regular functionality. Without detailed information, usort is a great starting point.Softhearted
I think you mean uksort(). @Oz: Yes, I think so, since the other alternative--creating a custom locale--strikes me as an incredible amount of effort/overkill.Fein
Question was about sorting by custom alphabet, not just about 'how to sort array'. It's not an answer, so -1.Glomma
@OZ_: It is a positive route to take given the information provided. If you can think of a better approach, go ahead and post it instead.Fein
@Darien, you not that man who can tell me what to do, so relax. And I have complete answer for this interesting question, and just because I know how to do it, I know that use usort it's not an answer.Glomma
the above function works of course but in my case the keys are strings which have to be sorted according to a preset alphabet for example "sleep" => "evening" should come after "awake" => "morning", giving array("awake"=>"morning", "sleep" => "evening"); but this must now be accomplished not with the english alphabet but with another alphabet (AjawbpfmnrhHxXsSqkgtTdD=)Lorileelorilyn
I have to agree with what has been previously commented. This answer is inadequate in respecting the complexity of the keys. It is not a solution that is readily useful in solving the asked question.Ecto
S
0

Given your $alphabet = "AjawbpfmnrhHxXsSqkgtTdD";, and assuming that A<j<a, etc, per your comment, transform each key in the alternative alphabet to a series in the known alphabet, e.g. use a mapping like:

  your alphabet: AjawbpfmnrhHxXsSqkgtTdD
 'real'alphabet: abcdefghijklmnopqrstuvw

So the key 'Ajaw' => 'abcd', and 'fmnr' => 'ghij', etc. This then turns your keys into something you can sort using conventional php functions. You'd need some way to handle characeters not present in your original alphabet though.

Something like that might work - you'd need two transform functions (from your alphabet to 'real' alphabet and vice versa), and then a comparator for e.g. uksort.

My two cents - thanks for clarifying the original question.

Softhearted answered 14/6, 2011 at 22:50 Comment(5)
This seems possible for a small text but when handling a lot of texts, this seems a long detour to come to the solution. What I'm looking for is something like the folowing in python: sorted_list = sorted(Unsorted_list, key=lambda (v, k): [alphabet.index(c) for c in v])Lorileelorilyn
I agree - it is not a particularly elegant solution.Softhearted
Compile yourself PHP 6, it has that build in.Fatherhood
@Fatherhood can you post the link to this php native function documentation?Bittner
@Bittner Don't remember it specifically, maybe strtr is it? php.net/strtr - The analogy to PHP 6 must have been a joke, there was never a release of it.Fatherhood
M
0

After feedback from @mickmackusa I have updated my example to work with uksrot and answer the question fully

$order = str_split("AjawbpfmnrhHxXsSqkgtTdD");

uksort($arr, function ($a, $b) use ($order) {
    $posA = array_search($a, $order);
    $posB = array_search($b, $order);
    return $posA - $posB;
});

http://sandbox.onlinephpfunctions.com/code/9b6f39b30dcc932517bbe82608dd8a0c8d35b3da

-- original response with usort--

You can use usort() with a custom order array like so

$arr = array("w","b","m","n","x","x","z","T","T","A","A");

$order = array("A","j","a","w","b","p","f","m","n","r","h","H","x","X","s","S","q","k","g","t","T","d","D"," ","=");
    usort($arr, function ($a, $b) use ($order) {
        $posA = array_search($a, $order);
        $posB = array_search($b, $order);
        return $posA - $posB;
    });

(you could probably just explode the $order string so it's nicer)

I actually just came across this answer which explains it better, and handles if a value is not inside the order array.

And a working example http://sandbox.onlinephpfunctions.com/code/3934aafe93377ec18549d326d6551608436242a7

Monticule answered 3/7, 2018 at 10:55 Comment(5)
I don't think this technique works as required. Please prove that it works by providing an online demo.Ecto
@updated with example. I am no longer using uksort and using usort as originally intendedMonticule
The OP doesn't want to sort by values. The core problem with your demo/answer is that you are ignoring the OP's requirements and sample data. This answer is incorrect.Ecto
Updated now to work with the answer with exampleMonticule
Your snippet is NOT using the OP's very clearly provided multi-character string keys. This answer does not respect the complexity of comparing keys which are longer than one character. If you are confused, read my newly posted and correct answer which respects the complexity of the OP's input data.Ecto
E
0

Fortunately, your custom alphabet does not have more characters than the list of single-byte latin letters, so translating is a very simple and readable process.

I recommend that you set up a translation array before you begin sorting, then translate/normalize the keys for the purpose of sorting.

Code: (Demo)

$array = [
    '=k_0' => ['test1'],
    'aA_2' => ['test2'],
    'sqA_1' => ['test3'],
    '=kj_0' => ['test4'],
    'awA_2' => ['test5'],
    '= D_1' => ['test6'],
    'sq A_1' => ['test7'],
    'sqA_2' => ['test8'],
];

$trans = ['AjawbpfmnrhHxXsSqkgtTdD =', 'abcdefghijklmnopqrstuvwxy'];

uksort(
    $array,
    function ($a, $b) use ($trans) {
        return strtr($a, ...$trans) <=> strtr($b, ...$trans);
    }
);
var_export($array);

Output:

array (
  'aA_2' => 
  array (
    0 => 'test2',
  ),
  'awA_2' => 
  array (
    0 => 'test5',
  ),
  'sqA_1' => 
  array (
    0 => 'test3',
  ),
  'sqA_2' => 
  array (
    0 => 'test8',
  ),
  'sq A_1' => 
  array (
    0 => 'test7',
  ),
  '=k_0' => 
  array (
    0 => 'test1',
  ),
  '=kj_0' => 
  array (
    0 => 'test4',
  ),
  '= D_1' => 
  array (
    0 => 'test6',
  ),
)

From PHP7.4, the syntax can be reduced using arrow function syntax.

uksort(
    $array,
    fn($a, $b) => strtr($a, ...$trans) <=> strtr($b, ...$trans)
);
Ecto answered 2/3, 2021 at 19:52 Comment(1)
@Fatherhood here it goes ^Ecto
G
-2
<?php
$arr = [8,10,12,18,20,7,4,6,2,20,0]; //take array

 $a= sortasc($arr); // call function

function sortasc($arr){


    for($i=0;$i<=count($arr);$i++){
            for($j=1;$j<=count($arr)-1;$j++){

                         if($arr[$j-1]>$arr[$j]){

                        $temp = $arr[$j];
                        $arr[$j]= $arr[$j-1];
                        $arr[$j-1] = $temp;
                    }
        }
    }
        return $arr;
}

?>
Gavriella answered 26/9, 2017 at 11:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.