LINUX.ORG.RU

Как обратиться к элементу многомерного массива по ключу, который находится в другом линейном массиве?

 , , ,


0

2

Есть многомерный ассоциативный массив. Надо обратиться к элементу массива по ключу, который записан в другом линейном массиве.

То есть, имеется многомерный массив данных и линейный массив с ключем:

$a=[
  'animals'=> [
    'cats' => [
      'catusdomesticus' => 'home',
      'pantera' => 'wild'
    ]
  ]
];

$keys=['animals', 'cats', 'pantera'];
Нужно сделать две вещи:

1. (простое) Получить значение $a['animals']['cats']['pantera']
2. (сложное) Удалить элемент $a['animals']['cats']['pantera']

Есть ли какой-либо быстрый (встроеный) в PHP5 способ такое сделать, или нужно городить собственный код?

Хотелось бы обойтись без кодогенерации и eval().

★★★★★

Конечно ничего встроенного для такой наркомании нет. Велосипед тем не менее очень простой.

$item =& $a;
foreach($keys as $key) $item =& $item[$key];
$item = 42; // whatever

Удалить элемент $a['animals']['cats']['pantera']

Думаю, что достаточно присвоить null.

no-such-file ★★★★★ ()
Ответ на: комментарий от lizard

Дураку понятно, что ключей может быть произвольное количество.

no-such-file ★★★★★ ()
Ответ на: комментарий от no-such-file

Думаю, что достаточно присвоить null.

Чему присвоить null?

Xintrea ★★★★★ ()
Ответ на: комментарий от Xintrea

Полученной ссылке на нужный элемент массива. Правда я чот не уверен, что это сработает. Возможно нужно будет как-то array_splice поработать.

no-such-file ★★★★★ ()
Последнее исправление: no-such-file (всего исправлений: 2)
Ответ на: комментарий от no-such-file

Как вариант можно запоминать «предыдущую» ссылку на массив (т.е. последний вложенный массив) и делать unset элемента этого массива по последнему ключу из массива ключей.

no-such-file ★★★★★ ()
Ответ на: комментарий от no-such-file

Ну вот попробовал и с unset и с null:

$item =& $a;
for($i=0; $i<count($keys); $i++)
{
  $item =& $item[$keys[$i]];

  if($i===count($keys)-1) {
    echo "\nDelete element:\n";
    var_dump($item);
   
    $item=null; // unset($item);
  }  
}  
var_dump( $a );


С unset() вообще ничего не происходит.

С null имеем просто изменение значения элемента:

'pantera' => NULL

Xintrea ★★★★★ ()
Ответ на: комментарий от no-such-file

Ага, вот так прокатило:

$item =& $a;
$beforeItem=null;
for($i=0; $i<count($keys); $i++)
{
  if($i>0)
    $beforeItem=&$item;

  $item=&$item[$keys[$i]];

  if($i===count($keys)-1) {
    echo "\nCurrent key:\n";
    var_dump($keys[$i]);

    echo "\nDelete element:\n";
    var_dump($item);

    echo "\nBefore item:\n";
    var_dump($beforeItem);

    // unset($item);

    unset( $beforeItem[$keys[$i]] );
  }  
}  
var_dump( $a );


Правда, этот код подходит только для массивов с размерностью больше единицы. Для одномерных массивов он работать не будет.

Xintrea ★★★★★ ()

Рекурсия тебе в помощь для произвольной размерности, isset() для проверки существования, unset() для удаления.

WARNING ★★★★ ()
Ответ на: комментарий от Xintrea

только для массивов с размерностью больше единицы

Ну ты и мудрила.

$item =& $a;
foreach($keys as $key) {
  $last_key = $key;
  $array =& $item;
  $item =& $item[$key];
}
$array[$last_key] = 42; // whatever
unset($array[$last_key]);
no-such-file ★★★★★ ()

Например так: packagist -> search ... -> array flatten или so

Специально встроенных средств для подобных задач скорее всего нет.

Очень отдаленно, монструозно и теоретически: json_encode, postgres insert, select «from json»

Как вариант, преобразовать в xml (simple) потом xpath-запросы например.

anonymous ()
Ответ на: комментарий от no-such-file

Ну ты и мудрила.

Мой код делает ровно то, что ты описал:

Как вариант можно запоминать «предыдущую» ссылку на массив (т.е. последний вложенный массив) и делать unset элемента этого массива по последнему ключу из массива ключей.



А твой код хренпойми как работает. У тебя нет сущности «предыдущая» ссылка, а если и есть, то называется просто $item. Момент, когда этот $item превращается в предыдущую ссылку у тебя не обозначен. Момент, когда достигается последний ключ у тебя тоже не обозначен, а ты о нем, опять же, говоришь. Зачем так писать код? Как сказал, так и надо писать, а не жонглировать переменными и ссылками.

Если бы ты сказал: «Надо пробежаться по линейному массиву ключей, на каждый ключ выдергивая ссылку на подмассив обрабатываемого многомерного массива. Тогда при завершении цикла останется ссылка на конечный подмассив, а обращение к ней с последним ключом из линейного массива ключей будет эквивалентно обращению к искомому элементу» тогда твой код был бы оправдан.

А если бы ты еще подумал и добавил: «В конце цикла последний перебраный ключ линейного массива атоматически будет являться ключем искомого элемента в конечном подмассиве», то ты бы понял что $last_key тебе нафиг не нужен, и написал бы так:

$item =& $a;
foreach($keys as $key) {
  $array =& $item;
  $item =& $item[$key];
}
$array[$key] = 42; // whatever
unset($array[$key]);

Xintrea ★★★★★ ()
Ответ на: комментарий от Xintrea

хренпойми как работает

ЛОЛ.

last_key тебе нафиг не нужен

Да, тут я лоханулся, забыл что foreach в пыхе не делает отдельную область видимости.

no-such-file ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.