Przełącz dwa elementy w tablicy asocjacyjnej


Przykład:
$arr = array( 'apple' => 'sweet',
'grapefruit' => 'bitter',
'pear' => 'tasty',
'banana' => 'yellow');

Chcę zmienić pozycje grejpfruta i gruszki, tak aby stała się tablica
$arr = array( 'apple' => 'sweet',
'pear' => 'tasty',
'grapefruit' => 'bitter',
'banana' => 'yellow')

Znam klucze i wartości elementów, które chcę przełączać, czy jest na to łatwy sposób? A może wymagałoby to pętli + utworzenia nowej tablicy?
podziękować
Zaproszony:
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Tylko trochę krótsze i mniej skomplikowane niż rozwiązanie Arcaneerudite:
<?php
if(!function_exists('array_swap_assoc')) {
function array_swap_assoc($key1, $key2, $array) {
$newArray = array ();
foreach ($array as $key => $value) {
if ($key == $key1) {
$newArray[$key2] = $array[$key2];
} elseif ($key == $key2) {
$newArray[$key1] = $array[$key1];
} else {
$newArray[$key] = $value;
}
}
return $newArray;
}
}$array = $arrOrig = array( 'fruit' => 'pear',
'veg' => 'cucumber',
'tuber' => 'potato',
'meat' => 'ham');$newArray = array_swap_assoc('veg', 'tuber', $array);var_dump($array, $newArray);
?>

Przetestowane i działa dobrze
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Oto moja wersja funkcji swap:
function array_swap_assoc(&$array,$k1,$k2) {
if($k1 === $k2) return;// Nothing to do $keys = array_keys($array);
$p1 = array_search($k1, $keys);
if($p1 === FALSE) return;// Sanity check...keys must exist $p2 = array_search($k2, $keys);
if($p2 === FALSE) return; $keys[$p1] = $k2;// Swap the keys
$keys[$p2] = $k1; $values = array_values($array);// Swap the values
list($values[$p1],$values[$p2]) = array($values[$p2],$values[$p1]); $array = array_combine($keys, $values);
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

jeśli tablica pochodzi z bazy danych, dodaj pole sort_order, aby zawsze mieć pewność, w jakiej kolejności elementy znajdują się w tablicy.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Nie jestem pewien, czy został wymieniony, ale jest to trudne, ponieważ nie jest indeksowane.
Weźmy:
$arrOrig = array( 'fruit'=>'pear',
'veg'=>'cucumber',
'tuber'=>'potato');

Zdobądź klucze:
$arrKeys = array_keys($arrOrig);
print_r($arrKeys);
Array( [0]=>fruit
[1]=>veg
[2]=>tuber)

Pobierz wartości:
$arrVals = array_values($arrOrig);
print_r($arrVals);
Array( [0]=>pear
[1]=>cucumber
[2]=>potato)

Teraz masz 2 tablice numeryczne. Zamień indeksy na te, które chcesz zamienić, a następnie przeczytaj drugą tablicę z powrotem w kolejności zmodyfikowanej tablicy liczbowej. Powiedzmy, że chcemy zamienić „owoce” i „warzywa”:
$arrKeysFlipped = array_flip($arrKeys);
print_r($arrKeysFlipped);
Array ( [fruit]=>0
[veg]=>1
[tuber]=>2)
$indexFruit = $arrKeysFlipped['fruit'];
$indexVeg = $arrKeysFlipped['veg'];
$arrKeysFlipped['veg'] = $indexFruit;
$arrKeysFlipped['fruit'] = $indexVeg;
print_r($arrKeysFlipped);
Array ( [fruit]=>1
[veg]=>0
[tuber]=>2)

Teraz możesz zamienić tablicę z powrotem:
$arrKeys = array_flip($arrKeysFlipped);
print_r($arrKeys);
Array ( [0]=>veg
[1]=>fruit
[2]=>tuber)

Możesz teraz zbudować tablicę, przechodząc przez tablicę oringal do „kolejności” przegrupowanych kluczy.
$arrNew = array ();
foreach($arrKeys as $index=>$key) {
$arrNew[$key] = $arrOrig[$key];
}
print_r($arrNew);
Array ( [veg]=>cucumber
[fruit]=>pear
[tuber]=>potato)

Nie testowałem tego - ale tego się spodziewałem. Czy to pomaga? Powodzenia :)
Możesz umieścić to w funkcji
$ arrNew = array_swap_assoc ($ key1, $ key2, $ arrOld);
<?php
if(!function_exists('array_swap_assoc')) {
function array_swap_assoc($key1='',$key2='',$arrOld=array()) {
$arrNew = array ();
if(is_array($arrOld) && count($arrOld) > 0) {
$arrKeys = array_keys($arrOld);
$arrFlip = array_flip($arrKeys);
$indexA = $arrFlip[$key1];
$indexB = $arrFlip[$key2];
$arrFlip[$key1]=$indexB;
$arrFlip[$key2]=$indexA;
$arrKeys = array_flip($arrFlip);
foreach($arrKeys as $index=>$key) {
$arrNew[$key] = $arrOld[$key];
}
} else {
$arrNew = $arrOld;
}
return $arrNew;
}
}
?>

OSTRZEŻENIE: proszę przetestować i zdebugować to przed samym użyciem - żadne testy nie zostały w ogóle wykonane.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Może to być opcja lub nie, w zależności od konkretnego przypadku użycia, ale jeśli zainicjujesz swoją tablicę do wartości null za pomocą odpowiednich kluczy przed wypełnieniem jej danymi, możesz ustawić wartości w dowolnej kolejności i oryginalny klucz porządek zostanie zachowany. Tym samym zamiast wymieniać elementy można uniknąć konieczności ich całkowitej wymiany:
$arr = array('apple' => null,
'pear' => null,
'grapefruit' => null,
'banana' => null);

...
$arr['apple'] = 'sweet';
$arr['grapefruit'] = 'bitter';// set grapefruit before setting pear
$arr['pear'] = 'tasty';
$arr['banana'] = 'yellow';
print_r($arr);>>> Array
( [apple] => sweet
[pear] => tasty
[grapefruit] => bitter
[banana] => yellow)
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Nie ma prostego sposobu, wystarczy pętla lub nowa definicja tablicy.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Klasyczna tablica asocjacyjna w żaden sposób nie definiuje ani nie gwarantuje kolejności elementów. Do tego celu służy prosta tablica/wektor. Jeśli używasz tablicy asocjacyjnej, zakłada się, że chcesz uzyskać dostęp losowy, ale nie sekwencyjny. W moim przypadku używasz tablicy assoc do zadania, dla którego nie została utworzona.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

tak, zgadzam się z Lexem, jeśli używasz tablicy asocjacyjnej do przechowywania danych, dlaczego nie użyć swojej logiki do obsługi dostępu do nich, a nie w zależności od tego, jak znajduje się w tablicy.
Jeśli naprawdę chcesz się upewnić, że są we właściwej kolejności, spróbuj utworzyć obiekty z owocami, a następnie umieść je w zwykłej tablicy.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Nie ma na to łatwego sposobu. Brzmi to jak mały błąd logiczny z Twojej strony, który skłonił Cię do podjęcia próby zrobienia tego, gdy istnieje lepszy sposób na zrobienie tego, co chcesz. Czy możesz nam powiedzieć, dlaczego chcesz to zrobić?
Mówisz, że
znam klucze i wartości elementów, które chcę zmienić
, co sprawia, że ​​myślę, że to, czego naprawdę chcesz, to funkcja sortowania, ponieważ w każdej chwili możesz łatwo uzyskać dostęp do elementów, które chcesz chcesz, tak jak oni.
$value = $array[$key];

Jeśli tak, to użyłbym

sort()
http://us.php.net/manual/en/function.sort.php
,

ksort()
http://us.php.net/manual/en/function.ksort.php
lub jedną z wielu innych funkcji sortowania, aby uzyskać tablicę tak, jak chcesz. Możesz nawet użyć usort ()

-
http://us.php.net/manual/en/function.usort.php
Sort an array by values using a user-defined comparison function
.
Alternatywnie możesz użyć

array_replace()
http://us.php.net/manual/en/fu ... e.php
jeśli kiedykolwiek będziesz musiał zamienić wartości lub klucze.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Oto dwa rozwiązania. Pierwsza jest dłuższa, ale nie tworzy tymczasowej tablicy, więc oszczędza pamięć. Drugi jest prawdopodobnie szybszy, ale zużywa więcej pamięci:
function swap1(array &$a, $key1, $key2)
{
if (!array_key_exists($key1, $a) || !array_key_exists($key2, $a) || $key1 == $key2) return false; $after = array();
while (list($key, $val) = each($a))
{
if ($key1 == $key)
{
break;
}
else if ($key2 == $key)
{
$tmp = $key1;
$key1 = $key2;
$key2 = $tmp;
break;
}
} $val1 = $a[$key1];
$val2 = $a[$key2]; while (list($key, $val) = each($a))
{
if ($key == $key2)
$after[$key1] = $val1;
else
$after[$key] = $val;
unset($a[$key]);
} unset($a[$key1]);
$a[$key2] = $val2; while (list($key, $val) = each($after))
{
$a[$key] = $val;
unset($after[$key]);
} return true;
}function swap2(array &$a, $key1, $key2)
{
if (!array_key_exists($key1, $a) || !array_key_exists($key2, $a) || $key1 == $key2) return false; $swapped = array(); foreach ($a as $key => $val)
{
if ($key == $key1)
$swapped[$key2] = $a[$key2];
else if ($key == $key2)
$swapped[$key1] = $a[$key1];
else
$swapped[$key] = $val;
} $a = $swapped; return true;
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Jest na to prosty sposób:
$sourceArray = array( 'apple' => 'sweet',
'grapefruit' => 'bitter',
'pear' => 'tasty',
'banana' => 'yellow');
// set new order
$orderArray = array( 'apple' => '',//this values would be replaced
'pear' => '',
'grapefruit' => '',
//it is not necessary to touch all elemets that will remains the same);
$result = array_replace($orderArray, $sourceArray);
print_r($result);

i otrzymujesz:
$result = array( 'apple' => 'sweet',
'pear' => 'tasty',
'grapefruit' => 'bitter',
'banana' => 'yellow')
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

fwiw jest tutaj funkcją do zamiany dwóch sąsiednich elementów w celu zaimplementowania moveUp () lub moveDown () na tablicy asocjacyjnej bez foreach ()
/**
* @param array $array to modify
* @param string $key key to move
* @param int $direction +1 for down | -1 for up
* @return $array
*/
protected function moveInArray($array, $key, $direction = 1)
{
if (empty($array)) {
return $array;
}
$keys = array_keys($array);
$index = array_search($key, $keys);
if ($index === false) {
return $array;// not found
}
if ($direction < 0) {
$index--;
}
if ($index < 0 || $index >= count($array) - 1) {
return $array;// at the edge: cannot move
} $a = $keys[$index];
$b = $keys[$index + 1];
$result = array_slice($array, 0, $index, true);
$result[$b] = $array[$b];
$result[$a] = $array[$a];
return array_merge($result, array_slice($array, $index + 2, null, true));
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

function arr_swap_keys(array &$arr, $key1, $key2, $f_swap_vals=false) {
// if f_swap_vals is false, then
// swap only the keys, keeping the original values in their original place
// ( i.e. do not preserve the key value correspondence )
// i.e. if arr is (originally)
// [ 'dog' => 'alpha', 'cat' => 'beta', 'horse' => 'gamma' ]
// then calling this on arr with, e.g. key1 = 'cat', and key2 = 'horse'
// will result in arr becoming:
// [ 'dog' => 'alpha', 'horse' => 'beta', 'cat' => 'gamma' ]
//
// if f_swap_vals is true, then preserve the key value correspondence
// i.e. in the above example, arr will become:
// [ 'dog' => 'alpha', 'horse' => 'gamma', 'cat' => 'beta' ]
//
// $arr_vals = array_values($arr);// is a (numerical) index to value mapping
$arr_keys = array_keys($arr);// is a (numerical) index to key mapping
$arr_key2idx = array_flip($arr_keys);
$idx1 = $arr_key2idx[$key1];
$idx2 = $arr_key2idx[$key2];
swap($arr_keys[$idx1], $arr_keys[$idx2]);
if ( $f_swap_vals ) {
swap($arr_vals[$idx1], $arr_vals[$idx2]);
}
$arr = array_combine($arr_keys, $arr_vals);
}function swap(&$a, &$b) {
$t = $a;
$a = $b;
$b = $t;
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Podzielę się również moją krótką wersją, działa zarówno z tablicami numerycznymi, jak i asocjacyjnymi.
array array_swap ( array $array , mixed $key1 , mixed $key2 [, bool $preserve_keys = FALSE [, bool $strict = FALSE ]] )

Zwraca nową tablicę ze zmienionymi dwoma elementami. Zachowuje oryginalne klucze, jeśli są dostępne. Zwróć FALSE, jeśli nie znaleziono żadnych kluczy.
function array_swap(array $array, $key1, $key2, $preserve_keys = false, $strict = false) {
$keys = array_keys($array);
if(!array_key_exists($key1, $array) || !array_key_exists($key2, $array)) return false;
if(($index1 = array_search($key1, $keys, $strict)) === false) return false;
if(($index2 = array_search($key2, $keys, $strict)) === false) return false;
if(!$preserve_keys) list($keys[$index1], $keys[$index2]) = array($key2, $key1);
list($array[$key1], $array[$key2]) = array($array[$key2], $array[$key1]);
return array_combine($keys, array_values($array));
}

Na przykład:
$arr = array_swap($arr, 'grapefruit', 'pear');
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Cóż, to tylko kluczowy problem z sortowaniem. W tym celu możemy użyć
uksort
. Potrzebuje funkcji porównania klucza i musimy tylko wiedzieć, że powinien zwrócić 0, aby pozostawić pozycję kluczową nienaruszoną, i coś innego niż 0, aby przesunąć klucz w górę lub w dół.
Zauważ, że zadziała to tylko wtedy, gdy klucze, które chcesz zamienić, znajdują się obok siebie.
<?php$arr = array( 'apple' => 'sweet',
'grapefruit' => 'bitter',
'pear' => 'tasty',
'banana' => 'yellow');uksort( $arr,
function ($k1, $k2) {
if ($k1 == 'grapefruit' && $k2 == 'pear') return 1;
else return 0;
});var_dump($arr);
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Z myślą o tym problemie napisałem bardziej ogólną funkcję.
  • tablica ze znanymi kluczami
  • określić kolejność kluczy w drugiej tablicy (klucze w tablicy $ order wskazują położenie klucza)

function order_array ($ array, $ order) {
foreach (array_keys($array) as $k => $v) {
$keys[++$k] = $v;
}
for ($i = 1; $i <= count($array); $i++) {
if (isset($order[$i])) {
unset($keys[array_search($order[$i], $keys)]);
}
if ($i === count($array)) {
array_push($keys, $order[$i]);
} else {
array_splice($keys, $i-1, 0, $order[$i]);
}
}
}
foreach ($keys as $key) {
$result[$key] = $array[$key];
}
return $resu<
} else {
return false;
}
}$order = array(1 => 'item3', 2 => 'item5');
$array = array("item1" => 'val1', "item2" => 'val2', "item3" => 'val3', "item4" => 'val4', "item5" => 'val5');print_r($array); -> Array ( [item1] => val1 [item2] => val2 [item3] => val3 [item4] => val4 [item5] => val5 ) print_r(order_array($array, $order)); -> Array ( [item3] => val3 [item5] => val5 [item1] => val1 [item2] => val2 [item4] => val4 )

Mam nadzieję, że jest to dla kogoś istotne/pomocne
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Tablice w php to uporządkowane mapy.
$arr = array('apple'=>'sweet','grapefruit'=>'bitter','
pear'=>'tasty','banana'=>'yellow');

nie oznacza to, że pierwszy element to „jabłko” = & > „słodki”, a ostatni to „banan” = & > „żółty” tylko dlatego, że słowo „jabłko” zostało umieszczone na pierwszym miejscu, a „banan” na końcu. Właściwie „jabłko” = & > „słodki” będzie pierwszym i
„banan” = & > „żółty” będzie na drugim miejscu ze względu na rosnącą kolejność alfabetyczną.

Aby odpowiedzieć na pytania, Zaloguj się lub Zarejestruj się