PHP arsort issue with keys - php

$vals = array(51, 23, 77, 3, 8, 31, 17, 102, 87);
arsort($vals);
From here, how can I get the keys of the 3 first values? If I do $vals[0] it won't work because it'll return me the original [0] key before the arsort.
I want to get the original keys of 102, 87 and 77 after arsort.

Depending on what you need it for, one way is
$keys = array_keys($vals);
$keys[0] will contain the first key.
$vals[$keys[0]] will contain the first value.
An alternate way
$part = array_slice($vals, 0, 3, true);
$part will contain three $key => $value pairs for the first three entries.
And for the first three keys, you can mix and match the above, such as:
$firstThree = array_keys(array_slice($vals, 0, 3, true));

$firstThreeKeys = array_slice(array_keys($vals), 0, 3);
echo join(', ', $firstThreeKeys);

I think I have found a method, maybe not the best however:
reset($arr); $key1=key($arr);
next($arr); $key2=key($arr);
next($arr); $key3=key($arr);

You could use array_keys()?
Alternatively, loop through the sorted array with a foreach and you can still get the keys:
$i = 0;
$numKeysToGet = 3;
$keys = array();
foreach ($vals as $k => $v) if ($i < $numKeysToGet) {
$keys[] = $k;
$i++;
} else break;
// $keys now contains the first three array keys

arsort saves key=>value relationship, so it's usualy used for associative arrays (hash). For your needs try to sort value=>key array instead of your key=>value with the standart sotring function. Otherwise you can use foreach loop (limit it with 3 iterations) to get the keys.

Related

maximum value in php array for each key value

I want to find out the maximum value of the each key in the array
$arr1= array(
0=>array(1,2,3),
1=>array(2,4,6),
2=>array(25,4,5));
}
I want to find the maximum value for each value for the corresponding key
The final output shuld be
$max_array = array(25,4,6);
with the below code i get error max(): When only one parameter is given, it must be an array in
foreach ($res_arr as $k=>$subArray) {
foreach ($subArray as $id=>$value) {
$spanmaxArray[$id] = max($value);
}
}
First, rotate array to makes columns as lines
$arr1= array(
0=>array(1,2,3),
1=>array(2,4,6),
2=>array(25,4,5)
);
$arr2 = array();
foreach($arr1 as $subArray) {
foreach($subArray as $k=>$v) {
$arr2[$k][] = $v;
}
}
Then, use array_map as #HamZa did
$max_array = array_map('max', $arr2);
print_r($max_array);
foreach ($res_arr as $k=>$subArray){
$max = 0;
foreach ($subArray as $id=>$value){
if ($value>$max){
$max = $value;
}
}
$spanmaxArray[$k] = $max;
}
Try this.
Definitely the shortest version:
$max_array = array_map('max', $arr1);
array_map() takes each element array of $arr1 and applies max() to it.
Edited after seeing that max in each column position is desired:
$sorted = array();
for ($i = 0; $i <=2; $i++) {
$sorted[$i] = array_column($input, $i);
}
This loops over the array and applies array_column() to each (requires PHP 5.5).
So:
$sorted = array();
for ($i = 0; $i <=2; $i++) {
$sorted[$i] = array_column($arr1, $i);
}
$max_array = array_map('max', $sorted);
working version
You only need one loop, because the max function takes an array as a parameter. But the answer you are giving is wrong, unless I've misunderstood the problem.
I think what you're after is:
$max_array = array_map('max', $arr1);
All of the earlier answers are working too hard.
Use array_map() as the iterating function.
Unpack your multidimensional array with the "spread/splat operator" (...); in other words, convert your single array containing three subarrays into three separate arrays.
Call max() on the three elements as they are synchronously iterated by array_map().
Code: (Demo)
$arr1 = [
[1, 2, 3],
[2, 4, 6],
[25, 4, 5],
];
var_export(array_map('max', ...$arr1));
The above is a more versatile and concise version of the following one-liner which has the same effect on the sample array:
var_export(array_map('max', $arr1[0], $arr1[1], $arr1[2]));
Output:
array (
0 => 25,
1 => 4,
2 => 6,
)
*A note for researchers: if processing a multidimensional array that has associative first level keys, you will need to index the first level so that the splat operator doesn't choke on the keys.
...array_values($array)

Using PHP remove duplicates from an array without using any in- built functions?

Lets say I have an array as follows :
$sampArray = array (1,4,2,1,6,4,9,7,2,9)
I want to remove all the duplicates from this array, so the result should be as follows:
$resultArray = array(1,4,2,6,9,7)
But here is the catch!!! I don't want to use any PHP in built functions like array_unique().
How would you do it ? :)
Here is a simple O(n)-time solution:
$uniqueme = array();
foreach ($array as $key => $value) {
$uniqueme[$value] = $key;
}
$final = array();
foreach ($uniqueme as $key => $value) {
$final[] = $key;
}
You cannot have duplicate keys, and this will retain the order.
A serious (working) answer:
$inputArray = array(1, 4, 2, 1, 6, 4, 9, 7, 2, 9);
$outputArray = array();
foreach($inputArray as $inputArrayItem) {
foreach($outputArray as $outputArrayItem) {
if($inputArrayItem == $outputArrayItem) {
continue 2;
}
}
$outputArray[] = $inputArrayItem;
}
print_r($outputArray);
This depends on the operations you have available.
If all you have to detect duplicates is a function that takes two elements and tells if they are equal (one example will be the == operation in PHP), then you must compare every new element with all the non-duplicates you have found before. The solution will be quadratic, in the worst case (there are no duplicates), you need to do (1/2)(n*(n+1)) comparisons.
If your arrays can have any kind of value, this is more or less the only solution available (see below).
If you have a total order for your values, you can sort the array (n*log(n)) and then eliminate consecutive duplicates (linear). Note that you cannot use the <, >, etc. operators from PHP, they do not introduce a total order. Unfortunately, array_unique does this, and it can fail because of that.
If you have a hash function that you can apply to your values, than you can do it in average linear time with a hash table (which is the data structure behind an array). See
tandu's answer.
Edit2: The versions below use a hashmap to determine if a value already exists. In case this is not possible, here is another variant that safely works with all PHP values and does a strict comparison (Demo):
$array = array (1,4,2,1,6,4,9,7,2,9);
$unique = function($a)
{
$u = array();
foreach($a as $v)
{
foreach($u as $vu)
if ($vu===$v) continue 2
;
$u[] = $v;
}
return $u;
};
var_dump($unique($array)); # array(1,4,2,6,9,7)
Edit: Same version as below, but w/o build in functions, only language constructs (Demo):
$array = array (1,4,2,1,6,4,9,7,2,9);
$unique = array();
foreach($array as $v)
isset($k[$v]) || ($k[$v]=1) && $unique[] = $v;
var_dump($unique); # array(1,4,2,6,9,7)
And in case you don't want to have the temporary arrays spread around, here is a variant with an anonymous function:
$array = array (1,4,2,1,6,4,9,7,2,9);
$unique = function($a) /* similar as above but more expressive ... ... you have been warned: */ {for($v=reset($a);$v&&(isset($k[$v])||($k[$v]=1)&&$u[]=$v);$v=next($a));return$u;};
var_dump($unique($array)); # array(1,4,2,6,9,7)
First was reading that you don't want to use array_unique or similar functions (array_intersect etc.), so this was just a start, maybe it's still of som use:
You can use array_flip PHP Manual in combination with array_keys PHP Manual for your array of integers (Demo):
$array = array (1,4,2,1,6,4,9,7,2,9);
$array = array_keys(array_flip($array));
var_dump($array); # array(1,4,2,6,9,7)
As keys can only exist once in a PHP array and array_flip retains the order, you will get your result. As those are build in functions it's pretty fast and there is not much to iterate over to get the job done.
<?php
$inputArray = array(1, 4, 2, 1, 6, 4, 9, 7, 2, 9);
$outputArray = array();
foreach ($inputArray as $val){
if(!in_array($val,$outputArray)){
$outputArray[] = $val;
}
}
print_r($outputArray);
You could use an intermediate array into which you add each item in turn. prior to adding the item you could check if it already exists by looping through the new array.

How to convert a simple array to an associative array?

What is the fastest way to convert a simple array to an associative array in PHP so that values can be checked in the isset($array[$value])?
I.e. fastest way to do the following conversion:
$array = array(1, 2, 3, 4, 5);
$assoc = array();
foreach ($array as $i => $value) {
$assoc[$value] = 1;
}
Your code is the exact equivalent of:
$assoc = array_fill_keys(array(1, 2, 3, 4, 5), 1); // or
$assoc = array_fill_keys(range(1, 5), 1);
array_flip(), while it may work for your purpose, it's not the same.
PHP ref: array_fill_keys(), array_flip()
If anyone is still wondering how to do this, there is an easier solution for this by using the array_combine function.
$array = array(1, 2, 3, 4, 5);
$assoc = array_combine($array,$array);
array_flip() is exactly doing that:
array_flip() returns an array in flip order, i.e. keys from trans become values and values from trans become keys.
Note that the values of trans need to be valid keys, i.e. they need to be either integer or string. A warning will be emitted if a value has the wrong type, and the key/value pair in question will not be flipped.
If a value has several occurrences, the latest key will be used as its values, and all others will be lost.
But apart from that, there is only one type of array in PHP. Even numerical ("simple", as you call it) arrays are associative.
Simply use this logic
$var1 = json_encode($arr1, JSON_FORCE_OBJECT);
$var1 = json_decode($var1);
where $arr1 is the array that has to be converted to associative array.
This can be achieved by json_encode and the json_decode the same
function simple_to_associative($array) {
$new_array = [];
$i = 0;
$last_elem = end($array);
$nr_elems = count($array);
foreach ($array as $index=>$value) {
if($i % 2 == 0 && $last_elem == $value) {
$new_array[$value] = '';
} elseif($i % 2 == 0) {
$new_array[$value] = $array[$index + 1];
}
$i++;
}
return $new_array;
}
Would work on any simple array of unlimited elements.

Efficient algorithm for detecting matches

I'm looking for an efficient algorithm for detecting equal values in an array of integers N size. It must return the indices of the matches.
Alas, I can't think of anything more clever then brute force with two loops.
Any help will be appreciated.
Thanks!
You could intersect the array. This finds all the values of array2 that are in array1
$array1 = array("a" => "green", "b" => "brown", "c" => "blue", "red");
$array2 = array("a" => "green", "yellow", "red");
$result_array = array_intersect_assoc($array1, $array2);
print_r($result_array);
Would return
Array
(
[a] => green
)
It returns an array with all of the keys and values of the matches. Basically you can provide an infinite number of arguments to the array_insert_assoc:
array_intersect_assoc($base_array, $arr1, $arr2 ...);
It will search $base_array for the values that are in all the subsequent arrays. That means that the key and value will be taken from the $base_array
You could also compare the keys by using:
array_intersect_keys($base_array, $arr1, $arr2, $arr3);
These loops are O(N^2). Is N big? If so, can you sort the array O(NlogN), then scan it O(N)? ... or am I missing something?
You can use a set to hold the recent values. For example,
results = empty list
set = empty set
foreach key, val in array:
if val is not in set: add val to set
else: add key to results
return results
Each look up of set is O(1), so this algo will results in O(n) instead of O(n^2) if nested-loop is used.
In case you want to keep track of multi-occurence like this array 1, 2, 3, 3, 2, 1 you can use a hash table with key is the value and value (of the corresponding key in table) is the list of indices. The result for the given array will look lik {1:0, 5; 2: 1, 4; 3: 2, 3}.
results = empty hashtable
for each key, val in array:
if val is not in results:
results[val] = new list()
results[val].append(key)
return results
Perhaps this?
$arr = array_map('unserialize', array_unique(array_map('serialize', $arr)));
From the question: How to remove duplicated 2-dimension array in PHP?
if ($arr !== array_map('unserialize', array_unique(array_map('serialize', $arr))))
{
// found duplicates
}
You don't have to go through all the array again for each element. Only test an element with the subsequent element in the array:
$array = /* huge array */;
$size = count($array);
for($i = 0; $i < $size; $i++)
{
for($j = $i + 1; $j < $size; $j++) // only test with the elements after $i
{
if($array[$i] == $array[$j])
return true; // found a duplicate
}
return false; // found no duplicate
}
That's the most efficient way I can think of. Adapt it to your need as you will.
If one of your arrays is reasonably static (that is you are comparing to the same array several times ) you could invert it.
That is set up another array which is keyed by value and returns the index into the real array.
$invert = array();
foreach ($cmptoarray as $ix => $ival) {
$invert[$ival] = $ix;
}
Then you simply need an if ( isset($invert[$compfrmarray[$i]) ) .... to check the number.
Note: this is only worth doing if you compare against the same array several times!
Just use an associative array mapping a value to its index:
foreach($array1 as $index => $value) {
$aa[$value] = $index;
}
foreach($array2 as $index => $value) {
if(isset($aa[$value])) {
echo 'Duplicate: . Index 1: '.$aa[$value].' Index 2: '.$index.'.';
}
}

How to search Array for multiple values in PHP?

I need to get the keys from values that are duplicates. I tried to use array_search and that worked fine, BUT I only got the first value as a hit.
I need to get both keys from the duplicate values, in this case 0 and 2. The search result output as an array would be good.
Is there a PHP function to do this or do I need to write some multiple loops to do it?
$list[0][0] = "2009-09-09";
$list[0][1] = "2009-05-05";
$list[0][2] = "2009-09-09";
$list[1][0] = "first-paid";
$list[1][1] = "1";
$list[1][2] = "last-unpaid";
echo array_search("2009-09-09",$list[0]);
You want array_keys with the search value
array_keys($list[0], "2009-09-09");
which will return an array of the keys with the specified value, in your case [0, 2]. If you want to find the duplicates as well, you can first make a pass with array_unique, then iterate over that array using array_keys on the original; anything which returns an array of length > 1 is a duplicate, and the result is the keys in which the duplicates are stored. Something like...
$uniqueKeys = array_unique($list[0])
foreach ($uniqueKeys as $uniqueKey)
{
$v = array_keys($list[0], $uniqueKey);
if (count($v) > 1)
{
foreach ($v as $key)
{
// Work with $list[0][$key]
}
}
}
In array_search() we can read:
If needle is found in haystack more
than once, the first matching key is
returned. To return the keys for all
matching values, use array_keys() with
the optional search_value parameter
instead.
The following combination of function calls will give you all duplicate values:
$a = array(1, 1, 2, 3, 4, 5, 99, 2, 5, 2);
$unique = array_unique($a); // preserves keys
$diffkeys = array_diff_key($a, $unique);
$duplicates = array_unique($diffkeys);
echo 'Duplicates: ' . join(' ', $duplicates) . "\n"; // 1 2 5
You can achieve that using array_search() by using while loop and the following workaround:
while (($key = array_search("2009-09-09", $list[0])) !== FALSE) {
print($key);
unset($list[0][$key]);
}
Source: cue at openxbox at php.net
For one-multidimensional array, you may use the following function to achieve that (as alternative to array_keys()):
function array_isearch($str, $array){
$found = array();
foreach ($array as $k => $v) {
if (strtolower($v) == strtolower($str)) {
$found[] = $k;
}
}
return $found;
}
Source: robertark, php.net
The PHP manual states in the Return Value section of the array_search() function documentation that you can use array_keys() to accomplish this. You just need to provide the second parameter:
$keys = array_keys($list[0], "2009-09-09");
$userdb=Array
(
(0) => Array
(
(uid) => '100',
(name) => 'Sandra Shush',
(url) => 'urlof100'
),
);
$key = array_search(100, array_column($userdb, 'uid'));

Categories