2013-03-15 11 views
7

mam następujący układ:Grupy kluczy tablicy na zakresy numerów, możliwe?

(
    [25] => 1 
    [26] => 3 
    [10] => 2 
    [24] => 1 
) 

został stworzony przy użyciu funkcji w PHP array_count_values().

Rzeczywista oryginalna tablica było coś takiego, zanim array_count_values ​​...

Array 
(
    [0] => 26 
    [1] => 
    [2] => 18 
    [3] => 28 
    [4] => 22 
    [5] => 21 
    [6] => 26 
    [7] => 
    [8] => 
    [9] => 
    [10] => 
    [11] => 
    [12] => 
    [13] => 
    [14] => 
    [15] => 
    [16] => 
    [17] => 
    [18] => 
    [19] => 
    [20] => 
) 

te są wiekowe, więc jak mogę grupa je w grupach wiekowych?

Powiedzmy chcę następujących grupach wiekowych: <= 1819-2627-32> 32

to ma wyglądać:

(
[<= 18] => 1 
[19-26] => 4 
[27-32] => 2 
[ > 32] => 1 
) 

Czy istnieje funkcja gotowy na to?

Moje rozwiązanie: Jednym żmudnym sposobem byłoby stworzenie zmiennych grup wiekowych. Niż foreach i zwiększ zmienną ++ dla konkretnej grupy wiekowej, jeśli kluczowe dopasowania mieszczą się w przedziale ($min <= $value) && ($value <= $max) ...

+1

nie ma wbudowanej funkcji PHP posortować tablicę na grupy. –

+1

Czy jesteś pewien, że oczekiwany wynik jest prawidłowy? Według danych wyjściowych 'array_count_values ​​()', masz 2 osoby w kategorii <18, 5 osób w kategorii 19-26 i nikt w pozostałych kategoriach. – nickb

+0

@nickb wynik jest niepoprawny, pomyłkowo wkleiłem tutaj wynik z mojej głowy ... –

Odpowiedz

9

Interesujący problem. Oto moje rozwiązanie. Po pierwsze, należy zdefiniować tablicę przedziałów wiekowych:

$age_ranges = array(
    array(0, 18), 
    array(19, 26), 
    array(27, 32), 
    array(33, 150) // I use 150 as the "max" age 
); 

Następnie mamy swoje wyjście array_count_values():

$array_count_values = array(25 => 1, 26 => 3, 10 => 2, 24 => 1); // From OP 

Teraz tworzymy tablicę wszystkich grup wiekowych, gdzie klawisze są wiek i wartości to liczba osób w tym wieku. Należy go posortować według kluczy do następnego kroku.

$all_ages = $array_count_values + array_fill(0, 150, 0); 
ksort($all_ages); 

Wreszcie pętla nad wszystkimi przedziałów wiekowych, kroić przedział wiekowy od tablicy $all_ages, a suma ich wartości produkować szereg przedziałów wiekowych, z jego wartości odpowiadającej ilu ludzi wpadł ten przedział wiekowy.

$result = array(); 
foreach($age_ranges as $range) { 
    list($start, $end) = $range; 
    $result["$start-$end"] = array_sum(array_slice($all_ages, $start, $end - $start + 1)); 
} 

print_r($result);yields the following output:

Array 
(
    [0-18] => 2 
    [19-26] => 5 
    [27-32] => 0 
    [33-150] => 0 
) 

Edit: Ponieważ nadal masz dostęp do swojej oryginalnej tablicy, można po prostu obliczyć, ile "niewiadomych" trzeba było na samym końcu:

$result['unknown'] = count(array_filter($original_array, function($el) { 
    return empty($el); 
})); 
+0

OP może użyć 'array_map()', aby uniknąć "pętli foreach", +1 nickb! – HamZa

+2

@HamZaDzCyberDeV: Nie widzę, w jaki sposób 'tablica_mapa' może pomóc tutaj. Plus "foreach" jest prawdopodobnie szybszy. –

+0

Co z niezdefiniowanymi wynikami? Przepraszam, że nie napisałem tego w OP. Ale muszę rozliczyć puste klucze, ponieważ są to użytkownicy, którzy nie określili wieku. Ale na wykresie kołowym robię to byłoby ważne, aby uwzględnić to również. –

1

Jeśli chcesz po prostu użyć macierzy przed array_count_values(), możesz użyć

$ages = array(
    0 => 26, 
    1 => 18, 
    2 => 28, 
    3 => 22, 
    4 => null, 
    5 => 21, 
    6 => 26, 
    7 => null); 

utworzyć pustą tablicę do wypełnienia

$final = array(
    'unknown' => 0, 
    '18' => 0, 
    '19_26' => 0, 
    '27_32' => 0, 
    '32' => 0, 
); 

array_walk($ages, function($age, $i, $final) { 
    if (!$age) { $final['unknown']++; return; } 
    if ($age <= 18) { $final['18']++; return; } 
    if ($age <= 26) { $final['19_26']++; return; } 
    if ($age <= 32) { $final['27_32']++; return; } 
    if ($age > 32) { $final['32']++; return; } 
}, &$final); 

wyjście z $ końcowy:

array (size=5) 
    'unknown' => int 2 
    18 => int 1 
    '19_26' => int 4 
    '27_32' => int 1 
    32 => int 0 
1

Po obejrzeniu tych wszystkich rozwiązań, pomyślałem, dlaczego nie przy użyciu regex z oryginalnej tablicy?

$ages = array(25, 26, 10, 24, 10, 26, 26, 32, 32, 54, 84, 4, 18, 5, 98, 27); 
$string = '#'. implode('#', $ages) . '#'; 
preg_match_all('/(#[0-9]#|#1[0-7]#)|(#1[8-9]#|#2[0-6]#)|(#2[7-9]#|#3[0-2]#)|(#3[3-9]#|#[4-9][0-9]#|#1[0-5][0-9]#)/', $string, $groups); 
$age_ranges = array('0-17' => count(array_filter($groups[1])), '18-26' => count(array_filter($groups[2])), '27-32' 
=> count(array_filter($groups[3])), '33-159' => count(array_filter($groups[4]))); 

print_r($age_ranges); 

wyjściowa:

Array 
(
    [0-17] => 2 
    [18-26] => 3 
    [27-32] => 1 
    [33-159] => 2 
) 
7

To brzmi jak doskonały przypadku map-zredukować.

Krok mapy: przekształć każdy wiek w jeden z 4 zakresów.

Zmniejszenie stopnia: zmień zakres na tablicę wyników zakresów.

Spróbujmy go:

$map = function($age) { 
    if (!$age) { 
     return 'unknown'; 
    } elseif ($age <= 18) { 
     return '<= 18'; 
    } elseif ($age <= 26) { 
     return '19-26'; 
    } elseif ($age <= 32) { 
     return '26-32'; 
    } 
    return '> 32'; 
} 

Więc w zasadzie tutaj, jesteśmy po prostu obracając każdy wiek w ciągu reprezentującego zakresie reprezentuje. Więc teraz będziemy mieli szereg zakresów, więc musimy zredukować że się podsumowanie (sumują się wszystkie z tych zakresów):

I wtedy funkcję zmniejszają:

$reduce = function($result, $age) { 
    $result[$age]++; 
    return $result; 
} 

Jest to dość prosty. Jeśli chcesz wesprzeć dynamiczne zakresy, to trzeba było trochę logiki tam, aby sprawdzić, czy wiek nie jest ustawiony (a następnie zainicjować go 0) ...

Więc teraz, stawiając je wszystkie razem:

$array = array(12, 63, 24, 34, 12, 10, 19,); // Your ages 
$data = array_map(function($age) { 
    if (!$age) { 
     return 'unknown'; 
    } elseif ($age <= 18) { 
     return '<= 18'; 
    } elseif ($age <= 26) { 
     return '19-26'; 
    } elseif ($age <= 32) { 
     return '26-32'; 
    } 
    return '> 32'; 
}, $array); 
$result = array_reduce($data, function($result, $age) { 
    $result[$age]++; 
    return $result; 
}, array('unknown' => 0, '<= 18' => 0, '19-26' => 0, '26-32' => 0, '> 32' => 0)); 

które następnie daje:

array(4) { 
    ["unknown"]=> int(0) 
    ["<= 18"]=> int(3) 
    ["19-26"]=> int(2) 
    ["26-32"]=> int(0) 
    ["> 32"]=> int(2) 
} 
Powiązane problemy