PHP traktuje wszystkie tablice jako asocjacyjne, więc nie ma żadnych wbudowanych funkcji. Czy ktoś może polecić dość skuteczny sposób sprawdzenia, czy tablica zawiera tylko klawisze numeryczne?
Zasadniczo chcę być w stanie odróżnić to:
$sequentialArray = array('apple', 'orange', 'tomato', 'carrot');
i to:
$assocArray = array('fruit1' => 'apple',
'fruit2' => 'orange',
'veg1' => 'tomato',
'veg2' => 'carrot');
if (isset($array[0]))
, co jest proste i szybkie. Oczywiście, powinieneś najpierw upewnić się, że tablica nie jest pusta, i powinieneś mieć trochę wiedzy na temat możliwej zawartości tablicy, aby metoda nie mogła zawieść (np. Mieszana liczba / asocjacja lub niesekwencyjna).Odpowiedzi:
Zadałeś dwa pytania, które nie są do końca równoważne:
Zastanów się, które z tych zachowań naprawdę potrzebujesz. (Może być tak, że albo zrobi to dla twoich celów.)
Na pierwsze pytanie (po prostu sprawdzenie, czy wszystkie klawisze są numeryczne) odpowiada dobrze kapitan kurO .
W przypadku drugiego pytania (sprawdzenie, czy tablica jest indeksowana zerowo i sekwencyjnie), możesz użyć następującej funkcji:
źródło
isSequential()
miałaby większy sens niżisAssoc()
. W takiej funkcji pustą tablicę należy traktować jako sekwencyjną. Formuła może byćarray() === $arr || !isAssoc($arr)
.array_key_exists
Zamiast tego należy użyć optymalizacji,isset
ponieważ jeśli element zerowy ma wartość zerową, zestaw zwróci wartość false niepoprawnie. Wartość null powinna zwykle być prawidłową wartością w takiej tablicy.Aby tylko sprawdzić, czy tablica ma klucze niecałkowite (a nie, czy tablica jest indeksowana sekwencyjnie czy zerowo):
Jeśli istnieje co najmniej jeden klucz ciągu,
$array
będzie traktowany jako tablica asocjacyjna.źródło
$isIndexed = array_values($arr) === $arr;
? Na co pytam: jak myślisz, jakarray_values()
działa? Jak myślisz, w jaki sposób===
działa w odniesieniu do tablic? Odpowiedź jest oczywiście taka, że iterują również w tablicy.var_dump([1.2 => 'foo', 1.5 => 'bar']);
, odkryjesz, że masz tablicę[1 => 'bar']
. W żaden sposób nie można znaleźć oryginalnego typu klucza. Tak, wszystko to jest okropne; Tablice PHP są zdecydowanie najgorszą częścią języka, a większość szkód jest nieodwracalna i zawdzięcza to pomysłowi użycia pojedynczej konstrukcji dla tradycyjnych tablic, a tradycyjne mapy skrótów były okropne od samego początku.function isAssociative($arr) { foreach ($arr as $key => $value) { if (is_string($key)) return true; } return false; }
array(1 => 'a', 0 => 'b', 2 => 'c')
stanie sięfalse
(tablica sekwencyjna), a powinien byćtrue
(tablica asocjacyjna). toolsqa.com/data-structures/array-in-programming Nie jestem pewien, czy klucz musi być w porządku rosnącym? (0, 1, ...)Z pewnością jest to lepsza alternatywa.
źródło
===
tracę czas na sprawdzanie, czy wartości są równe, mimo że interesują nas tylko klucze. Z tego powodu wolę$k = array_keys( $arr ); return $k === array_keys( $k );
wersję.Wielu komentujących to pytanie nie rozumie, jak tablice działają w PHP. Z dokumentacji tablicy :
Innymi słowy, nie ma czegoś takiego jak klucz tablicy „8”, ponieważ zawsze będzie (cicho) konwertowany na liczbę całkowitą 8. Dlatego próba rozróżnienia liczb całkowitych i ciągów liczbowych jest niepotrzebna.
Jeśli chcesz najskuteczniejszego sposobu sprawdzenia tablicy pod kątem kluczy niecałkowitych bez robienia kopii części tablicy (jak robi to array_keys ()) lub wszystkich (jak foreach robi):
Działa to, ponieważ key () zwraca NULL, gdy bieżąca pozycja tablicy jest niepoprawna, a NULL nigdy nie może być prawidłowym kluczem (jeśli spróbujesz użyć NULL jako klucza tablicy, zostanie on po cichu przekonwertowany na „”).
źródło
0
docount($array)-1
, w tej ścisłej kolejności. Pomocnais_array()
może być wstępna kontrola . Dodaj rosnącą zmienną, aby sprawdzić sekwencję klawiszy:for ($k = 0, reset($array) ; $k === key($array) ; next($array)) ++$k;
To rozstrzygnie umowę.foreach
zamiast jawnej iteracji jest około dwa razy szybsze.function isAssocStr($array) { for (reset($array); is_int(key($array)); next($array)) { if (is_null(key($array))) return false; } return true; }
Jak stwierdził PO :
napisanie funkcji, która sprawdza, czy tablica jest asocjacyjna, nie jest rozsądne (IMHO) . Po pierwsze: co jest kluczem w tablicy PHP ?:
Oznacza to, że są 3 możliwe przypadki:
Możemy sprawdzić każdy przypadek za pomocą następujących funkcji.
Przypadek 1: wszystkie klucze są liczbami / liczbami całkowitymi .
Uwaga : Ta funkcja zwraca wartość true również dla pustych tablic.
Przypadek 2: wszystkie klucze są ciągami znaków .
Uwaga : Ta funkcja zwraca wartość true również dla pustych tablic.
Przypadek 3. niektóre klucze są ciągami , niektóre klucze są liczbami / liczbami całkowitymi .
Uwaga : Ta funkcja zwraca wartość true również dla pustych tablic.
Wynika, że:
(co jest z definicji, jak w „ pustym zestawie jest podzbiór dowolnego zestawu A, ponieważ wszystkie jego elementy należą do A ”).
Teraz, aby tablica była „prawdziwą” tablicą, do której wszyscy jesteśmy przyzwyczajeni, co oznacza:
Możemy to sprawdzić za pomocą następującej funkcji.
Przypadek 3a klucze są liczbowe / całkowite , sekwencyjne i zerowe .
Uwaga : Ta funkcja zwraca wartość true również dla pustych tablic.
Ostrzeżenia / pułapki (lub jeszcze bardziej osobliwe fakty na temat kluczy tablic w PHP)
Klucze całkowite
Kluczami dla tych tablic są liczby całkowite :
Klucze strunowe
Kluczami do tych tablic są ciągi znaków :
Klucze całkowite, które wyglądają jak łańcuchy
Jeśli uważasz, że klucz
array("13" => "b")
jest ciągiem , jesteś w błędzie . Z dokumentu tutaj :Na przykład kluczem do tych tablic są liczby całkowite :
Ale kluczem do tych tablic są ciągi :
Co więcej, zgodnie z dokumentem ,
Tak więc kluczem do tej tablicy może być lub nie być liczbą całkowitą - to zależy od platformy.
Co gorsza, PHP ma tendencję do błędów, jeśli liczba całkowita znajduje się w pobliżu granicy 2 31 = 2 147 483 648 (patrz błąd 51430 , błąd 52899 ). Na przykład w moim lokalnym środowisku (PHP 5.3.8 na XAMPP 1.7.7 na Windows 7)
var_dump(array("2147483647" => "b"))
dajeale w tej wersji demonstracyjnej na żywo na codepad (PHP 5.2.5) daje to samo wyrażenie
Zatem kluczem jest liczba całkowita w jednym środowisku, ale ciąg znaków w innym, mimo że
2147483647
jest to 32-bitowa liczba całkowita ze znakiem .źródło
Pod względem prędkości:
Pod względem pamięci:
źródło
źródło
array('1'=>'asdf', '2'=>'too')
będzie traktowany jako tablica asocjacyjna, podczas gdy tak naprawdę nie jest (klucze są tak naprawdę ciągami znaków)true
jeśli kluczami są: zero, liczby całkowite (tylko dodatnie), pusty ciąg znaków lub dowolna kombinacja powyższych, na przykład ciąg „09”. Ta funkcja nie uwzględnia kolejności kluczy. Takarray(0=>'blah', 2=>'yep', 3=>'wahey')
,array(0=>'blah', 2=>'yep', 1=>'wahey')
iarray('blah', 'yep', 'wahey')
to wszystko asocjacyjne według tej funkcji, aarray('a'=>'blah', 'b'=>'yep', 'c'=>'wahey')
nie jest.W rzeczywistości najbardziej efektywnym sposobem jest:
Działa to, ponieważ porównuje klucze (które dla tablicy sekwencyjnej są zawsze 0,1,2 itd.) Z kluczami kluczy (które zawsze będą 0,1,2 itd.).
źródło
true
naarray(1=>"a")
alefalse
zaarray("a"=>"a")
. Bardziej sensowne byłoby!=
zastąpienie go przez!==
.[0] == ['a']
w PHP (od0 == 'a'
, i rzeczywiście0 == 'banana'
).==
Operator PHP jest szalony.Użyłem obu
array_keys($obj) !== range(0, count($obj) - 1)
iarray_values($arr) !== $arr
(które są podwójnymi względem siebie, chociaż drugi jest tańszy niż pierwszy), ale oba zawodzą w przypadku bardzo dużych tablic.To dlatego, że
array_keys
iarray_values
są bardzo kosztowne operacje (ponieważ zbudować zupełnie nową tablicę o rozmiarze mniej więcej, że z oryginałem).Następująca funkcja jest bardziej niezawodna niż metody przedstawione powyżej:
Zauważ też, że jeśli nie chcesz rozróżniać rzadkich tablic od tablic asocjacyjnych, możesz po prostu wrócić
'assoc'
z obuif
bloków.Wreszcie, chociaż może się to wydawać znacznie mniej „eleganckie” niż wiele „rozwiązań” na tej stronie, w praktyce jest znacznie wydajniejsze. Niemal każda tablica asocjacyjna zostanie wykryta natychmiast. Tylko indeksowane tablice zostaną sprawdzone wyczerpująco, a metody opisane powyżej nie tylko sprawdzą indeksowane tablice wyczerpująco, ale je powielają.
źródło
Myślę, że następujące dwie funkcje są najlepszym sposobem na sprawdzenie „czy tablica jest asocjacyjna czy numeryczna”. Ponieważ „numeryczne” może oznaczać tylko klawisze numeryczne lub tylko sekwencyjne klawisze numeryczne, poniżej wymieniono dwie funkcje, które sprawdzają jeden z warunków:
Pierwsza funkcja sprawdza, czy każdy klawisz jest liczbą całkowitą. Druga funkcja sprawdza, czy każdy klucz jest liczbą całkowitą, a ponadto sprawdza, czy wszystkie klucze są sekwencyjne, zaczynając od $ base, która domyślnie wynosi 0, a zatem można je pominąć, jeśli nie trzeba podawać innej wartości podstawowej. key ($ my_array) zwraca null, jeśli wskaźnik odczytu zostanie przesunięty poza koniec tablicy, co kończy pętlę for i sprawia, że instrukcja po pętli for true jest prawdziwa, jeśli wszystkie klucze były liczbami całkowitymi. Jeśli nie, pętla kończy się przedwcześnie, ponieważ klucz jest typu string, a instrukcja po pętli for zwróci false. Ta ostatnia funkcja dodatkowo dodaje jeden do $ base po każdym porównaniu, aby móc sprawdzić, czy następny klucz ma poprawną wartość. Ścisłe porównanie sprawia, że sprawdza się również, czy klucz jest typu liczba całkowita. $ Base = (int) $ base część w pierwszej sekcji pętli for można pominąć, gdy $ base zostanie pominięte lub jeśli upewnisz się, że jest wywoływana tylko za pomocą liczby całkowitej. Ale ponieważ nie mogę być pewien wszystkich, zostawiłem to. W każdym razie instrukcja jest wykonywana tylko raz. Myślę, że są to najbardziej wydajne rozwiązania:
Pamiętaj, że klucz tablicy może być tylko liczbą całkowitą lub łańcuchem, a łańcuch ściśle liczbowy, taki jak „1” (ale nie „01”), zostanie przetłumaczony na liczbę całkowitą. To sprawia, że sprawdzanie klucza liczb całkowitych jest jedyną potrzebną operacją oprócz liczenia, jeśli chcesz, aby tablica była sekwencyjna. Oczywiście, jeśli is_indexed_array zwraca false, tablica może być postrzegana jako asocjacyjna. Mówię „widziałem”, bo tak naprawdę wszyscy są.
źródło
Ta funkcja obsługuje:
pomysł jest prosty: jeśli jeden z kluczy NIE jest liczbą całkowitą, jest to tablica asocjacyjna, w przeciwnym razie jest sekwencyjna.
źródło
Zauważyłem dwa popularne podejścia do tego pytania: jedno za pomocą,
array_values()
a drugie za pomocąkey()
. Aby dowiedzieć się, co jest szybsze, napisałem mały program:Dane wyjściowe dla programu w PHP 5.2 na CentOS są następujące:
Dane wyjściowe w PHP 5.3 dały podobne wyniki. Oczywiście korzystanie
array_values()
jest znacznie szybsze.źródło
$arrays = Array( 'Array #1' => range(0, 50000), );
Jednym ze sposobów podejścia do tego jest skorzystanie z funkcji piggyback
json_encode
, która ma już własną wewnętrzną metodę rozróżniania między tablicą asocjacyjną a tablicą indeksowaną w celu uzyskania poprawnego JSON.Możesz to zrobić, sprawdzając, czy pierwszy znak zwrócony po kodowaniu to
{
(tablica asocjacyjna) lub[
(tablica indeksowana).źródło
Istnieje już wiele odpowiedzi, ale oto metoda, na której Laravel polega w swojej klasie Arr:
Źródło: https://github.com/laravel/framework/blob/5.4/src/Illuminate/Support/Arr.php
źródło
array_keys($keys)
zwróci sekwencyjną tablicę liczb (0 ... X), która ma tę samą długość oryginalnej tablicy. Na przykładarray_keys(["a", "b", "c"]) = [0, 1, 2];
array_keys([0, 1, 2]) = [0, 1, 2]
(jest to tablica sekwencyjna, ponieważ[0, 1, 2] !== [0, 1, 2]
). Kolejny przykład:array_keys(["a" => 5, "b" => 7, "c" => 10]) = ["a", "b", "c"];
array_keys(["a", "b", "c"]) = [0, 1, 2]
(jest to tablica asocjacyjna, ponieważ["a", "b", "c"] !== [0, 1, 2]
). Mam nadzieję, że to jasne (trudne do wyjaśnienia w komentarzu, przynajmniej dla mnie)Szybka, zwięzła i wydajna pamięć. Bez kosztownych porównań, wywołań funkcji i kopiowania tablic.
źródło
Korzystając z rozszerzenia xarray PHP
Możesz to zrobić bardzo szybko (około 30+ razy szybciej w PHP 5.6):
Lub:
źródło
Wiem, że dodawanie odpowiedzi do tej wielkiej kolejki jest nieco bezcelowe, ale oto czytelne rozwiązanie O (n), które nie wymaga powielania żadnych wartości:
Zamiast sprawdzać klucze, czy wszystkie są numeryczne, iterujesz po klawiszach, które byłyby tam dla tablicy numerycznej i upewniasz się, że istnieją.
źródło
[1,2,null,4]
zawiedzie, ale jest to poprawna tablica. więc dodałem pewne ulepszenia na stackoverflow.com/a/25206156/501831 zarray_key_exists
kontrolą dodawania )isset()
jest niewłaściwym narzędziem, ponieważ zwróci wartość false, jeśli wartość jest ustawiona, ale jestnull
, jak wskazał @lazycommit.Moje rozwiązanie:
array_merge
na jednej tablicy reindeksuje wszystkieinteger
klucze, ale nie inne. Na przykład:Więc jeśli tworzona jest lista (tablica niepowiązana), to
['a', 'b', 'c']
wartość jest usuwana,unset($a[1])
a następniearray_merge
wywoływana, lista jest ponownie indeksowana, zaczynając od 0.źródło
O(n)
w dodatkowej pamięci (ponieważ stworzyło wiele nowych tablic z tyloma elementami$array
), odpowiedź nie rozwiązuje dwuznaczności zadanego pytania ani nie wyjaśnia dokładnie, w jaki sposób definiuje tablicę listy / niepowiązaną tablicę, a nawet jeśli żaden z tych punktów nie był prawdziwy, nie jest jasne, czy to dodaje wartości w porównaniu z innymi odpowiedziami już opublikowanymi.Po kilku lokalnych testach porównawczych, debugowaniu, sondowaniu kompilatora, profilowaniu i nadużywaniu 3v4l.org do porównywania kolejnych wersji (tak, dostałem ostrzeżenie, aby przestać) i porównywania z każdą odmianą, jaką mogłem znaleźć ...
Podaję ci funkcję testu macierzy asocjacyjnej opartej na analizie macierzy według najlepszego, przeciętnego i najgorszego przypadku, która w najgorszym przypadku jest w przybliżeniu tak dobra lub lepsza niż wszystkie inne scenariusze średnich przypadków.
Od https://3v4l.org/rkieX :
źródło
Oto metoda, której używam:
Pamiętaj, że nie uwzględnia to szczególnych przypadków, takich jak:
Niestety nie mogę ci w tym pomóc. Jest również dość wydajny w przypadku tablic o przyzwoitych rozmiarach, ponieważ nie tworzy niepotrzebnych kopii. To te małe rzeczy sprawiają, że Python i Ruby są o wiele ładniejsi w pisaniu ...: P
źródło
Oba te przykłady, które uzyskały najwięcej punktów, nie działają poprawnie z takimi tablicami
$array = array('foo' => 'bar', 1)
źródło
To też działałoby ( demo ):
Należy pamiętać, że głównym celem tej odpowiedzi jest poinformowanie Cię o istnieniu
SplFixedArray
i nie zachęcanie do korzystania z wyjątków dla tego rodzaju testów.źródło
Myślę, że definicja tablicy skalarnej będzie się różnić w zależności od aplikacji. Oznacza to, że niektóre aplikacje będą wymagały bardziej ścisłego wyczucia tego, co kwalifikuje się jako tablica skalarna, a niektóre aplikacje będą wymagały bardziej luźnego wyczucia.
Poniżej przedstawiam 3 metody o różnej surowości.
źródło
Jeszcze jeden szybki ze źródła . Dopasuj kodowanie
json_encode
(ibson_encode
). Podobnie jak zgodność z javascript Array.źródło
isset
iarray_key_exists
? czy to drugie nie wystarczy?isset()
czek tutaj jest całkowicie zbędny.isset()
jest szybszy niżarray_key_exists()
. patrz ilia.ws/archives/…null
s, ale to też nie jest tak prawdopodobne, że masz tablicę wystarczająco dużą, aby zauważalna była różnica wydajności za pomocą obu kontrolijson_encode
, możesz po prostu sprawdzić pierwszy symbol łańcucha, zwrócony przezjson_encode($your_arr)
- czy to[
lub{
;-)Czy to może być rozwiązanie?
Zastrzeżeniem jest oczywiście to, że kursor tablicy został zresetowany, ale powiedziałbym, że prawdopodobnie funkcja jest używana, zanim tablica zostanie jeszcze przemierzona lub użyta.
źródło
array("a", "b")
iarray("a", "b" => "B")
ponieważ sprawdza tylko pierwszy klucz. BTW,is_long
to tylko pseudonimis_int
.[7 => 'foo', 2 => 'bar']
jako „mieszaną” tablicę, która jest częściowo, ale nie „czysto” sekwencyjna. Wydaje mi się, że jest to po prostu niewłaściwe użycie słów.Wiele z tych rozwiązań jest eleganckich i ładnych, ale nie skaluje się dobrze i wymaga dużej ilości pamięci lub procesora. Większość tworzy 2 nowe punkty danych w pamięci za pomocą tego rozwiązania z obu stron porównania. Im większa matryca, tym trudniejszy i dłuższy proces i używana pamięć oraz utrata korzyści z oceny zwarcia. Zrobiłem kilka testów z kilkoma różnymi pomysłami. Próba uniknięcia tablicy_klucza_istnieje, ponieważ jest to kosztowne, a także unikanie tworzenia nowych dużych zestawów danych do porównania. Wydaje mi się, że jest to prosty sposób na stwierdzenie, czy tablica jest sekwencyjna.
Uruchamiasz jedną liczbę na głównej tablicy i zapisujesz jedną liczbę całkowitą. Następnie zapętlasz tablicę i sprawdzasz dokładne dopasowanie podczas iteracji licznika. Powinieneś mieć od 1, aby liczyć. Jeśli zawiedzie, nastąpi zwarcie, co daje wzrost wydajności, gdy jest fałszywy.
Pierwotnie robiłem to z pętlą for i sprawdzaniem isset ($ arr [$ i]), ale to nie wykryje pustych kluczy, które wymagają tablicy_klucz_istniejących, a jak wiemy, jest to najgorsza funkcja do użycia dla prędkości.
Ciągłe aktualizowanie zmiennych za pomocą foreach w celu sprawdzenia wraz z iteratorem, który nigdy nie rośnie, jego rozmiar jest liczbą całkowitą, wykorzystajmy PHP, jest on wbudowany w optymalizację pamięci, buforowanie i wyrzucanie elementów bezużytecznych, aby utrzymać bardzo niskie zużycie zasobów.
Będę również argumentować, że użycie kluczy tablicowych w foreach jest głupie, kiedy można po prostu uruchomić $ key => $ wartość i sprawdzić klucz. Po co tworzyć nowy punkt danych? Po wyodrębnieniu kluczy macierzy natychmiast zużyłeś więcej pamięci.
źródło
odpowiedzi są już podane, ale zbyt wiele dezinformacji dotyczących wydajności. Napisałem ten mały skrypt porównawczy, który pokazuje, że metoda Foreach jest najszybsza.
Uwaga: następujące metody zostały skopiowane z innych odpowiedzi
wyniki:
źródło
Lub możesz po prostu użyć tego:
który sprawdzi, czy tablica zawiera jakiś klucz nienumeryczny lub:
aby sprawdzić, czy tablica jest ściśle sekwencyjna (zawiera automatycznie generowane klucze int od 0 do n-1 )
za pomocą tej biblioteki.
źródło
Jeśli PHP nie ma wbudowanego do tego celu, nie będziesz w stanie tego zrobić w mniej niż O (n) - wyliczając wszystkie klucze i sprawdzając typ liczb całkowitych. W rzeczywistości chcesz również upewnić się, że nie ma żadnych dziur, więc Twój algorytm może wyglądać następująco:
Ale po co zawracać sobie głowę? Załóżmy, że tablica jest tego typu, którego oczekujesz. Jeśli tak nie jest, po prostu wybuchnie ci w twarz - to dla ciebie dynamiczne programowanie! Przetestuj swój kod, a wszystko będzie dobrze ...
źródło
Porównuję różnicę między kluczami tablicy a kluczami wyniku array_values () tablicy, która zawsze będzie tablicą z indeksami liczb całkowitych. Jeśli klucze są takie same, nie jest to tablica asocjacyjna.
źródło
O(n)
dodatkową pamięć, gdy$array
man
przedmioty, a pisanie(someboolean) ? false : true
zamiast!someboolean
jest okropne i nieokreślone.