NOVINKA - Online rekvalifikační kurz Java programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.
NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!

Diskuze: Seřazení pole - rsort() Ale čísla první

V předchozím kvízu, Online test znalostí PHP, jsme si ověřili nabyté zkušenosti z kurzu.

Aktivity
Avatar
Erik Šťastný:17.10.2016 12:02

Zdravím, potřeboval bych prosím poradit, jak už říká titulek.

Příklad:

["5","2","1","D","BC","A"]

Standartní rsort():

["D","BC","A","5","2","1"]

Já potřebuji:

["5","2","1","A","BC","D"]

Nenakopne mě prosím někdo? :)

Editováno 17.10.2016 12:03
 
Odpovědět
17.10.2016 12:02
Avatar
Milan Gallas
Tvůrce
Avatar
Odpovídá na Erik Šťastný
Milan Gallas:17.10.2016 12:41

Ahoj, zkus jako druhý parametr dát - SORT_NUMERIC

 
Nahoru Odpovědět
17.10.2016 12:41
Avatar
Odpovídá na Milan Gallas
Erik Šťastný:17.10.2016 13:05

Už jsem zkoušel to se setřídí úplně "zvláštně"

 
Nahoru Odpovědět
17.10.2016 13:05
Avatar
Jakub Mareš
Člen
Avatar
Jakub Mareš:17.10.2016 15:23

Ahoj zkoušel jsem pár věcí, ale ani mně žádná nešla. Už mě napadá snad jen rozdělit pole, potom seřadit obě pole pomocí rsort a sort a potom je zase spojit.

 
Nahoru Odpovědět
17.10.2016 15:23
Avatar
Jakub Mareš
Člen
Avatar
Odpovídá na Jakub Mareš
Jakub Mareš:17.10.2016 15:27

Pole rozdělit podle toho jestli to je, nebo není číslo.

 
Nahoru Odpovědět
17.10.2016 15:27
Avatar
Odpovídá na Jakub Mareš
Erik Šťastný:17.10.2016 15:34

Jo to jsme dva napadlo mě to stejné, tak to teda zkusím no :)

 
Nahoru Odpovědět
17.10.2016 15:34
Avatar
Odpovídá na Erik Šťastný
Erik Šťastný:17.10.2016 15:45

I když to je šílené, nikdy nevím kolik prvních znaků bude číslo nebo text :-O

 
Nahoru Odpovědět
17.10.2016 15:45
Avatar
Jakub Mareš
Člen
Avatar
Odpovídá na Erik Šťastný
Jakub Mareš:17.10.2016 16:17

Ahoj použij foreach loop a funkci is_numeric.

 
Nahoru Odpovědět
17.10.2016 16:17
Avatar
Odpovídá na Jakub Mareš
Erik Šťastný:17.10.2016 16:20

Nejspíš jsem špatně popsal zádání stringy jsou ve formátu třeba "115-0226 XMU_China", takže asi nemůžu zkoušet is_numeric :/

 
Nahoru Odpovědět
17.10.2016 16:20
Avatar
Jakub Mareš
Člen
Avatar
Jakub Mareš:17.10.2016 16:29

Zkus se podívat jestli není nějáký způsob pomocí regexu, ale s regexem nemám zkušenosti, takže asi už jinak neporadím. Zkusil bych se zeptat na stack exchange, pokud ti tu nikdo jiný nedokáže poradit.

 
Nahoru Odpovědět
17.10.2016 16:29
Avatar
Odpovídá na Jakub Mareš
Erik Šťastný:17.10.2016 17:03

Jo to já fakt taky ne ani nevím o co jde :) Už to řeším na stackoverflow :)

 
Nahoru Odpovědět
17.10.2016 17:03
Avatar
Milan Gallas
Tvůrce
Avatar
Odpovídá na Erik Šťastný
Milan Gallas:18.10.2016 0:27

Tak ono je to těžké, když všechno mícháš dohromady. Ve většině případů stačí použít toto:

$exampleArray2 = ["5","2","1","D","BC","A"];
asort($exampleArray2, SORT_STRING | SORT_FLAG_CASE | SORT_NATURAL);
var_dump($exampleArray2);

echo '<br>';

rnatsort($exampleArray2);

function rnatsort(&$a){
    natsort($a);
    $a = array_reverse($a, true);
    var_dump($a);
}

ale ani jeden z výpisu ti na 100% nevihoví

 
Nahoru Odpovědět
18.10.2016 0:27
Avatar
VelkyBubak
Člen
Avatar
VelkyBubak:18.10.2016 4:31

Možná by šlo zápis 115-0226 XMU_China roztrhat na čtyři části, každou vložit jako jedno pole záznamu do DB, pomocí DB setřídit a znovu vypsat do php. Pokud jsou oddělovače vždy první pomlčka, druhý mezera a třetí podtržítko, a zápis je číslo číslo text text, mohlo by to fungovat. Otázkou zůstává, zda to má smysl a zda je přístupná DB.

 
Nahoru Odpovědět
18.10.2016 4:31
Avatar
Odpovídá na Milan Gallas
Erik Šťastný:18.10.2016 8:37

Když ono je to těžké když se před pár lety změnil formát zapisování zakázek, ale vedení je chce pořád mít seřazené :D

 
Nahoru Odpovědět
18.10.2016 8:37
Avatar
Odpovídá na VelkyBubak
Erik Šťastný:18.10.2016 8:38

Bohužel ani jedno :(

 
Nahoru Odpovědět
18.10.2016 8:38
Avatar
Erik Šťastný:18.10.2016 8:51

Prozatím jsem se rozhodl pro řešení ve stylu "If is_numeric"

function cmp($a, $b) {
    if ($a == $b) {
        return 0;
    }
    if (is_numeric(substr($a, 0, 1)) && (is_numeric(substr($b, 0, 1)))){
                return ($a < $b) ? 1 : -1;
        }
        if (is_numeric(substr($a, 0, 1)) && (!is_numeric(substr($b, 0, 1)))){
                return -1;
        }
        if (!is_numeric(substr($a, 0, 1)) && (is_numeric(substr($b, 0, 1)))){
                return 1;
        }
        return ($a < $b) ? 1 : -1;
}

uasort($sem, 'cmp');

Nicméně to kontroluje pouze první znak, zatím se to ale zdá dostačující :)

 
Nahoru Odpovědět
18.10.2016 8:51
Avatar
Odpovídá na Erik Šťastný
Erik Šťastný:18.10.2016 8:56

Pro toho komu se nechce louskat kód, podmínka spočívá v tom, že pokud je první znak ve stringu číslo, tak je považován automaticky za větší než text

 
Nahoru Odpovědět
18.10.2016 8:56
Avatar
Odpovídá na Erik Šťastný
Neaktivní uživatel:18.10.2016 11:04

A co nějak takhle?
Přetřídí pole obsahující mix formátů '115-0226 XMU_China', 'XMU_China' a '358-1947', tak že třídí první číslem začínající řetězce sestupně a následně písmenné řetězce vzestupně. Pokud je řetězec ve formátu "115-0226 XMU_China" setřídí ho nejprve podle čísla sestupně a při stejných číslech podle písmenné části vzestupně.

Určitě se to dá napsat líp :-)

<?php
/** @var  $a Vstupní pole */
$a = ["115-0226 XMU_China","114-0226 SMU_India","113-0226 KMU_Japan","112-0226 XMU_China","112-0224 XMU_India","112-0224 XMU_China", "XMU_China", "KDS_Korea", "XMU_Japan", "358-1947"];

/**
 * Vytvoří vícenásobné pole
 * @param $array Vstupní pole pro rozdělení řetezců na čísla a písmena
 * @return array
 */
function buildMultiArray($array)
{
    foreach ($array as $key => $value){
        if (preg_match('/^[a-zA-Z]+/', $value)){
            $data[0] = null;
            $data[1] = $value;
        }
        else{
            $data = explode(" ", $value);
        }
        if (empty($data[1])){
            $data[1] = null;
        }
        $nums[] = $data[0];
        $chars[] = $data[1];
    }
    $ar =[$nums, $chars];
    return $ar;
}

/**
 * Sestavení výstupního pole
 * @param $array Vstupní vícenásobné pole pro zjednodušení
 * @return array
 */
function rebuildArray($array)
{
    foreach ($array[0] as $key => $value){
        $ar[] = ltrim(rtrim($value ." ". $array[1][$key], " "), " ");
    }
    return $ar;
}

/**
 * Přetřídí vstupní pole
 * @param $array Vstupní pole pro třídění
 * @return array
 */
function sortArray($array)
{
    $ar = buildMultiArray($array);
    array_multisort($ar[0], SORT_DESC, SORT_NUMERIC,
        $ar[1], SORT_ASC, SORT_STRING);
    $sortedArray = rebuildArray($ar);
    return $sortedArray;
}

echo "Vstupní pole\n";
print_r($a);
echo "\nSetříděné pole\n";
print_r(sortArray($a));

Výstup je následující

Vstupní pole
Array
(
    [0] => 115-0226 XMU_China
    [1] => 114-0226 SMU_India
    [2] => 113-0226 KMU_Japan
    [3] => 112-0226 XMU_China
    [4] => 112-0224 XMU_India
    [5] => 112-0224 XMU_China
    [6] => XMU_China
    [7] => KDS_Korea
    [8] => XMU_Japan
    [9] => 358-1947
)

Setříděné pole
Array
(
    [0] => 358-1947
    [1] => 115-0226 XMU_China
    [2] => 114-0226 SMU_India
    [3] => 113-0226 KMU_Japan
    [4] => 112-0224 XMU_China
    [5] => 112-0226 XMU_China
    [6] => 112-0224 XMU_India
    [7] => KDS_Korea
    [8] => XMU_China
    [9] => XMU_Japan
)
Nahoru Odpovědět
18.10.2016 11:04
Neaktivní uživatelský účet
Avatar
Odpovídá na Neaktivní uživatel
Neaktivní uživatel:18.10.2016 11:21

už vidím chybku :-D
zapomněl sem tam z pokusů parametr SORT_NUMERIC, ale třídit se to má jako string

Nahoru Odpovědět
18.10.2016 11:21
Neaktivní uživatelský účet
Avatar
Odpovídá na Neaktivní uživatel
Erik Šťastný:20.10.2016 9:00

Hezké :) nicméně už jsem bohužel musel odevzdat řešení když tu todle ještě nebylo, myslím, že formát zakázek se nám hodně dlouho nezmění, tak snad moje řešení bude zatím stačit :D

Použil jsem to o pár komentářů nahoře, kde když string začíná číslem považuje se automaticky za větší než string co nezačíná :)

 
Nahoru Odpovědět
20.10.2016 9:00
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 20 zpráv z 20.