Модераторы: skyboy, MoLeX, Aliance, ksnk

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Сортировка ключей массива по шаблону 
V
    Опции темы
Aliance
Дата 4.3.2015, 11:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


I ♥ <script>
****


Профиль
Группа: Модератор
Сообщений: 6418
Регистрация: 2.8.2004
Где: spb

Репутация: 14
Всего: 137



А как бы вы решили следующую задачу:

Имеем массив, допустим такой:
Код

$a = [
    'aaa' => '1',
    'bbb' => '2',
    'ccc' => '3',
    'ddd' => '4',
    'eee' => '5',
];


И имеем шаблон сортировки его по ключам, допустим такой:
Код

$e = [
    'ddd',
    'bbb',
    'aaa',
];


В итоге должны получить следующее:
Код

$sorted = [
    'ddd' => '4',
    'bbb' => '2',
    'aaa' => '1',
    'ccc' => '3',
    'eee' => '5',
];

PM MAIL WWW ICQ Skype   Вверх
sQu1rr
Дата 4.3.2015, 13:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 597
Регистрация: 11.11.2008
Где: london

Репутация: 2
Всего: 13



А какие вообще условия. Нужно оптимально быстро, или максимально коротко, или просто красиво? А значения у ключей всегда идут по возрастанию от 1? А в шаблоне ключи всегда присутсвуют в массиве?
Код

uksort($a, function($l, $r) {
    global $e;
    $li = array_search($l, $e);
    $ri = array_search($r, $e);
    if ($li === false) return 1;
    elseif ($ri === false) return -1;
    return  $li - $ri;
});

PM MAIL Skype GTalk   Вверх
Aliance
Дата 4.3.2015, 14:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


I ♥ <script>
****


Профиль
Группа: Модератор
Сообщений: 6418
Регистрация: 2.8.2004
Где: spb

Репутация: 14
Всего: 137



На самом деле условия немного некорректны изначально. Потому что в асс. массиве не может быть важен порядок. Но так уж сложилось, что работает "как есть" :(
Из вышеперечисленного важно все, наиболее важна, конечно, скорость, но не в потерю читаемости. Два вызова array_search в цикле - это дороговато smile

ПС: Ключи и значения выбраны случайно. Задача обобщена. В частном виде, нужно поменять местами два элемента асс. массива, зная их ключи.
PM MAIL WWW ICQ Skype   Вверх
sQu1rr
Дата 4.3.2015, 14:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 597
Регистрация: 11.11.2008
Где: london

Репутация: 2
Всего: 13



Цитата(Aliance @  4.3.2015,  11:00 Найти цитируемый пост)
Два вызова array_search в цикле - это дороговато 

Можно перед вызовом функции закешировать индексы в отдельный ас. массив.

Цитата(Aliance @  4.3.2015,  11:00 Найти цитируемый пост)
В частном виде, нужно поменять местами два элемента асс. массива, зная их ключи. 

А можно пример? Я просто не вижу практического применения задачи. Я до этого даже не знал что можно сортировать ключи smile
PM MAIL Skype GTalk   Вверх
Aliance
Дата 4.3.2015, 14:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


I ♥ <script>
****


Профиль
Группа: Модератор
Сообщений: 6418
Регистрация: 2.8.2004
Где: spb

Репутация: 14
Всего: 137



Цитата(sQu1rr @  4.3.2015,  15:16 Найти цитируемый пост)
А можно пример?

Структура навигации хранится в массиве, в рамках A/B тестирования нужно тестовой группе поменять местами два элемента меню.
PM MAIL WWW ICQ Skype   Вверх
sQu1rr
Дата 4.3.2015, 14:36 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 597
Регистрация: 11.11.2008
Где: london

Репутация: 2
Всего: 13



Это можно сделать созданием нового массива, то есть за O(n)
Код

function dict_swap($dict, $key1, $key2) {
    $result = [];
    foreach ($dict as $key => $value) {
        if ($key == $key1) {
            $result[$key2] = $dict[$key2];
        } elseif ($key == $key2) {
            $result[$key1] = $dict[$key1];
        } else {
            $result[$key] = $value;
        }
    }
    return $result;
}

Быстрее уж некуда, нету такого способа о котором я бы знал
PM MAIL Skype GTalk   Вверх
Aliance
Дата 5.3.2015, 15:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


I ♥ <script>
****


Профиль
Группа: Модератор
Сообщений: 6418
Регистрация: 2.8.2004
Где: spb

Репутация: 14
Всего: 137



Написал примерно так:
Код

<?php

class Test {
    public static function run() {
        $elementsForSwap = [
            'bbb' => 'ddd',
            'ddd' => 'bbb',
        ];

        $a = [
            'aaa' => '1111',
            'bbb' => '2222222',
            'ccc' => '33',
            'ddd' => '4444444',
            'eee' => '5',
        ];

        var_dump($a);
        echo PHP_EOL;
        var_dump(self::swapElements($a, $elementsForSwap));
        echo PHP_EOL;
    }

    protected static function swapElements($oldElements, $elementsForSwap) {
        $elements = [];

        foreach ($oldElements as $key => $value) {
            if (in_array($key, $elementsForSwap, true)) {
                $elements[$elementsForSwap[$key]] = $oldElements[$elementsForSwap[$key]];
            } else {
                $elements[$key] = $value;
            }
        }

        return $elements;
    }
}

Test::run();


Все правильно делает, но вот если один из элементов отсутствует, то во-первых фатал (ну это лечится-то легко, isset`ом, но при этом задача не проходит уже тесты).

Получается нужно не просто поменять два элемента местами, а нужно некоторые элементы поставить на определенную позицию. В примере выше это элемент с ключом bbb (второй по порядку) нужно сделать четвертым, а четвертый ddd - вторым. При этом нужно чтобы все работало даже, если одно из (bbb или ddd) не будет (позиции соответственно сдвигаются тогда). Получается даже нужно отталкиваться не от порядковой позиции, а от позиции найденного элемента. Что не вычислить без второго цикла. В общем мне нужен отпуск  smile 
PM MAIL WWW ICQ Skype   Вверх
whatisnot
Дата 6.3.2015, 01:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 130
Регистрация: 14.12.2014

Репутация: 1
Всего: 2



Код

$m = array_combine($e, array_intersect_key($a, array_flip($e))) + array_diff_key($a, array_flip($e));

print_r($m);


А нет, значения сволочь переставит от сортировки. Надо подумать, что-то вертится на языке... )

Вот так:

Код

$e = array_flip($e);
$m = array_replace($e, array_intersect_key($a, $e)) + array_diff_key($a, $e);


Это сообщение отредактировал(а) whatisnot - 6.3.2015, 01:37
PM MAIL   Вверх
ksnk
Дата 6.3.2015, 08:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прохожий
****


Профиль
Группа: Комодератор
Сообщений: 6855
Регистрация: 13.4.2007
Где: СПб

Репутация: 96
Всего: 386



Aliance, Если набор полей массива ограничен и нужно постоянно выдавать результат в определенном порядке и аборе полей (вывод полей csv, например). То можно иметь уже отсортированный правильно массив ключей и array_merge' ем подсовывать туда данные
Код

$tpl=array(
    'ddd'=>'',
    'bbb'=>'',
    'aaa'=>'',
);
$data=array(
    'aaa' => '1',
    'bbb' => '2',
    'ccc' => '3',
    'ddd' => '4',
    'eee' => '5',
);
print_r(array_merge($tpl,$data));

Решение, вероятно, из разряда "коротких". Хотя должно быть и довольно быстро.


--------------------
Человеку свойственно ошибаться, программисту свойственно ошибаться профессионально ! user posted image
PM MAIL WWW Skype   Вверх
Aliance
Дата 6.3.2015, 09:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


I ♥ <script>
****


Профиль
Группа: Модератор
Сообщений: 6418
Регистрация: 2.8.2004
Где: spb

Репутация: 14
Всего: 137



Цитата(ksnk @  6.3.2015,  09:11 Найти цитируемый пост)
То можно иметь уже отсортированный правильно массив ключей

как отсортировать-то? smile
PM MAIL WWW ICQ Skype   Вверх
ksnk
Дата 6.3.2015, 09:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прохожий
****


Профиль
Группа: Комодератор
Сообщений: 6855
Регистрация: 13.4.2007
Где: СПб

Репутация: 96
Всего: 386



Aliance, А как формируется изначальный массив с правильным порядком ключей? Вот так же. Явно определить smile 


--------------------
Человеку свойственно ошибаться, программисту свойственно ошибаться профессионально ! user posted image
PM MAIL WWW Skype   Вверх
Aliance
Дата 6.3.2015, 12:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


I ♥ <script>
****


Профиль
Группа: Модератор
Сообщений: 6418
Регистрация: 2.8.2004
Где: spb

Репутация: 14
Всего: 137



ksnk, то как он формируется менять нельзя. можно работать только со сформированным, меняя там элементы. поменять порядок в асс. массиве можно только пересобрав его smile
PM MAIL WWW ICQ Skype   Вверх
ksnk
Дата 6.3.2015, 13:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прохожий
****


Профиль
Группа: Комодератор
Сообщений: 6855
Регистрация: 13.4.2007
Где: СПб

Репутация: 96
Всего: 386



Aliance, Тоесть, на момент, когда нужно сортировать есть только массив с именами полей?
функция array_fill_keys поможет состряпать нужный формат.
Код

$e=array(
   'ddd',
    'bbb',
    'aaa',
);
$data=array(
    'aaa' => '1',
    'bbb' => '2',
    'ccc' => '3',
    'ddd' => '4',
    'eee' => '5',
);

$tpl=array_fill_keys($e,'');
print_r(array_merge($tpl,$data));



--------------------
Человеку свойственно ошибаться, программисту свойственно ошибаться профессионально ! user posted image
PM MAIL WWW Skype   Вверх
Aliance
Дата 6.3.2015, 16:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


I ♥ <script>
****


Профиль
Группа: Модератор
Сообщений: 6418
Регистрация: 2.8.2004
Где: spb

Репутация: 14
Всего: 137



ksnk, ты, видимо, отталкивался от условия из первого поста, а в ходе обсуждения я его конкретизировал. нужно поменять местами два элемента в асс. массиве, зная их ключи, соблюдая следующие условия:
- обоих ключей может не быть - тогда ничего не делаем
- может не быть одного из ключей - тогда нужно второй элемент поставить на то место, где должен был бы быть первый. вот это "должен был бы быть" весьма кривое понятие, потому что:
-- элементы могут быть отсортированы в рандомном порядке до выполнения моего кода, соответственно я не знаю эту позицию заранее
-- элементы могут быть удалены (unset) до моего кода, соответственно я не знаю, будут ли они оба в момент исполнения моего кода.

В общем такие трудности возникли из-за неграмотной архитектуры конкретного участка кода, решил задачу костыльно - вызываю свой презентер сразу после объявления массива, гарантируя, что оба элемента в нем присутствуют, просто их меняю местами функцией, как предложили выше, а потом они могут быть удалены (unset) ниже по коду, но они уже примут нужное мне положение.
PM MAIL WWW ICQ Skype   Вверх
ksnk
Дата 6.3.2015, 17:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прохожий
****


Профиль
Группа: Комодератор
Сообщений: 6855
Регистрация: 13.4.2007
Где: СПб

Репутация: 96
Всего: 386



Aliance, угу, извиняюсь . Так далеко я ниасилил :( 


--------------------
Человеку свойственно ошибаться, программисту свойственно ошибаться профессионально ! user posted image
PM MAIL WWW Skype   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "PHP"
Aliance
IZ@TOP
skyboy
SamDark
MoLeX

Новичкам:

  • PHP редакторы собираются и обсуждаются здесь
  • Электронные книги по PHP, документацию можно найти здесь
  • Интерпретатор PHP, полную документацию можно скачать на PHP.NET

Важно:

  • Не брезгуйте пользоваться тегами [code=php]КОД[/code] для повышения читабельности текста/кода.
  • Перед созданием новой темы воспользуйтесь поиском и загляните в FAQ
  • Действия модераторов можно обсудить здесь

Внимание:

  • Темы "ищу скрипт", "подскажите скрипт" и т.п. будут переноситься в форум "Web-технологии"
  • Темы с именами: "Срочно", "помогите", "не знаю как делать" будут УДАЛЯТЬСЯ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, IZ@TOP, skyboy, SamDark, MoLeX, awers.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | PHP: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0601 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.