PHP: searching in the first "column" of an array of arrays [duplicate] - php

This question already has answers here:
PHP multidimensional array search by value
(23 answers)
Closed last year.
I have an array of arrays and I want to copy the first column
The data looks like this:
(0 => "homer", 1 => 1, 2 => 2, 3 => 3)
(0 => "marge", 1 => 2, 2 => 4, 3 => 8)
(0 => "bart", 1 => 6, 2 => 2, 3 => 7)
(0 => "lisa", 1 => 16, 2 => 20, 3 => 71)
Is there a PHP function (similar to array_search) which I can use to search for a name match in the first "column" ?
The data in the first column is already sorted so if I could copy "column1", I could carry out a array_search (which I assume uses a bsearch, rather than a naive element by element iteration).
My questions are:
Is there a PHP function similar to array_search, which I can use to search for matching items in the 1st column of the 2D array?
Failing that, is there a PHP function to copy the first column into a 1D array (whilst preserving order) so I can call array_search on it ?

Is there a PHP function similar to array_search, which I can use to search for matching items in the 1st column of the 2D array?
You could use array_filter
$matchedArray = array_filter($myArray, function($x) use ($nameToSearchFor) {
return $x[0] == $nameToSearchFor;
});
Then given:
$myArray = array(
array(0=>"homer", 1=> 1, 2=> 2, 3=> 3),
array(0 => "marge", 1=> 2, 2 => 4, 3=> 8),
array(0 => "bart", 1 => 6, 2 => 2, 3 => 7),
array(0 => "lisa", 1 => 16, 2 => 20, 3 => 71),
);
$nameToSearchFor = "bart";
Would produce:
$matchedArray === array(0 => "bart", 1 => 6, 2 => 2, 3 => 7);
I've used closures, that only work in PHP 5.3.0, but you use a traditional callback or create_function in older versions of php
Failing that, is there a PHP function to copy the first column into a 1D array (whilst preserving order) so I can call array_search on it ?
See deceze's first option. I see no need repeating a perfectly good answer.

$oneDarray = array_map(create_function('$a', 'return $a[0];'), $twoDarray);
Or:
foreach ($twoDarray as $values) {
if ($values[0] == 'homer') {
// found!
break;
}
}

This question came top on my Google search for array search column. It took me some time to find this better answer to the same question. By Mark M.
If you are using PHP >= 5.5, then you can use the new array_column(), >in conjunction with array_keys() and array_map().
Applied to this question, to search for "bart", it would be:
$array=array(
array(0=>"homer", 1=> 1, 2=> 2, 3=> 3),
array(0 => "marge", 1=> 2, 2 => 4, 3=> 8),
array(0 => "bart", 1 => 6, 2 => 2, 3 => 7),
array(0 => "lisa", 1 => 16, 2 => 20, 3 => 71));
$result = $array[array_search("bart",array_column($array, 0))];
print_r($result);
/* Output:
Array
(
[0] => bart
[1] => 6
[2] => 2
[3] => 7
)
*/
Run demo

PHP doesn't have a good clean way of doing this that I know of. However, you can do it yourself using a binary-search since the array is already sorted by the values in the first column of its child arrays. Here is the code to accomplish this:
<?php
// Binary Search Taken By greenmr:
// http://php.net/manual/en/function.array-search.php#89413
function array_bsearch( $needle, $haystack, $comparator ) {
$high = Count( $haystack ) -1;
$low = 0;
while ( $high >= $low ){
$probe = Floor( ( $high + $low ) / 2 );
$comparison = $comparator( $haystack[$probe], $needle );
if ( $comparison < 0 ) {
$low = $probe +1;
} elseif ( $comparison > 0 ) {
$high = $probe -1;
} else {
return $probe;
}
}
return -1;
}
// Compare the needle the first element/column
function KeyCompare( $obj, $needle) {
if ( $obj[0] < $needle ) {
return -1;
} elseif ( $obj[0] > $needle ) {
return 1;
} else {
return 0;
}
}
$arr = array(array(0=>"homer", 1=> 1, 2=> 2, 3=> 3),
array(0 => "marge", 1=> 2, 2 => 4, 3=> 8),
array(0 => "bart", 1 => 6, 2 => 2, 3 => 7),
array(0 => "lisa", 1 => 16, 2 => 20, 3 => 71));
$index = array_bsearch( 'marge', $arr, 'KeyCompare' );
// prints the array containing marge
echo print_r($arr[$index]);
?>

You could convert the array to use keys using an array_walk
$new_data = array();
array_walk($data, create_function('a','$new_data[$a[0]] = $a;'));
$search_text = 'bart';
if (array_key_exists($new_data, $search_text)) {
echo "I found '$search_text': ".print_r($new_data[$search_text], true);
}

Related

PHP Multidimensional array searching for combinations of values in array

I have a multidimensional array:
$array =
Array (
[0] => Array ( [id] => 2 [zoneId] => 2 [buildingId] => 2 [typeId] => 2 )
[1] => Array ( [id] => 4 [zoneId] => 2 [buildingId] => 2 [typeId] => 1 )
[2] => Array ( [id] => 6 [zoneId] => 6 [buildingId] => 17 [typeId] => 2 ) )
And I would like to search if the combination of, for example, [buildingId] => 2, [typeId] => 2 exists is array 0, 1 or 2.
I tried the following:
$keyType = array_search(2, array_column($array, 'typeId'));
$keyBuilding = array_search(2, array_column($array, 'buildingId'));
if(is_numeric($keyType)&&is_numeric($keyBuilding)){
echo 'Combination does exists'
}
This works, but gives also a false positive if I would search for [buildingId] => 17, [typeId] => 1. How can I solve this?
edit
I would also like to know if a combination is not in the array, how can I arrange that?
if($result == false){
echo 'does not exists';
}
You can try this code:
$keyTypeExistsAndHaveSameValue = isset($array['typeId']) && $array['typeId'] === 2;
$keyBuildingExistsAndHaveSameValue = isset($array['buildingId']) && $array['buildingId'] === 2;
if($keyTypeExistsAndHaveSameValue && $keyBuildingExistsAndHaveSameValue){
echo 'Combination does exists'
}
This code check if typeId & buildingId keys exist but it also check if its values are 2 and 2.
$buildingId = 2;
$typeId = 2;
$result = false;
foreach ($array as $key => $val) {
if ($val['buildingId'] == $buildingId && $val['typeId'] == $typeId) {
$result = $key; // If you want the key in the array
$result = $val; // If you want directly the entry you're looking for
break; // So that you don't iterate through the whole array while you already have your reuslt
}
}
I think what you need is this
$keyType = array_search(1, array_column($array, 'typeId'));
$keyBuilding = array_search(17, array_column($array, 'buildingId'));
if(is_numeric($keyType)||is_numeric($keyBuilding)){
echo 'Combination does exists';
}
Now here you need or operator instead of and operator because you want either typeid = 1 exists or building id = 17 exists.
If I have understand your question correctly then you are trying to do something like this, right ?
Hope this helps!
You would need to do a foreach loop to get the actual array number, the other solution don't seems to answer what you're looking for, which is to get the index number.
I would like to search if the combination of, for example, [buildingId] => 2, [typeId] => 2 exists is array 0, 1 or 2.
EDIT: This code is just sample code to show how you would get the array index number, in a production environment you would save the matching arrays, comparison figures are not hard coded, etc...
$array = array(array('id' => 2, 'zoneId' => 2, 'buildingId' => 2, 'typeId' => 2),
array('id' => 4, 'zoneId' => 2, 'buildingId' => 2, 'typeId' => 2),
array('id' => 6, 'zoneId' => 6, 'buildingId' => 17, 'typeId' => 2));
foreach ($array as $building => $building_details)
{
if ($building_details['buildingId'] === 2 && $building_details['typeId'] === 2)
{
echo 'Array number ' . $building . ' matches criteria<br>';
}
}
Output:
Array number 0 matches criteria
Array number 1 matches criteria
You can view this snippet online here.

PHP Export Indexed Array into CSV [duplicate]

This question already has answers here:
Add elements to array which has gapped numeric keys to form an indexed array / list
(5 answers)
Closed 5 months ago.
I have a following indexed array
$export_data = array (
[0] => 1,
[1] => 2,
[2] => 3,
[3] => 4,
[4] => 5,
[8] => 9,
[9] => 10,
);
I know how to export it to csv using fputcsv. However what my issue is that I need to export the data into correct column i.e. value in $export_data[8] needs to be exported in column 9 not column 6.
How can this be done please ?
Here you go, boss.
$export_data = array_replace(array_map(function($v){return null;}, range(0, max(array_keys($export_data)))), $export_data);
Tested 100,000 iterations and results are in seconds:
Version Run1 Run2 Run3
PHP 5.6.20 .58 .55 .50
PHP 7.0.5 .18 .21 .21
Now for the explanation so I don't get flogged with downvotes or get accused of witchcraft.
$export_data = array (
0 => 1,
1 => 2,
2 => 3,
3 => 4,
4 => 5,
8 => 9,
9 => 10,
);
$export_data =
array_replace( // replace the elements of the 10-item array with your original array and the filled-in blanks are going to be null. I did not use array_merge() because it would append $export_data onto our dynamic range() array rather than replacing elements as needed.
array_map( // loop the 10-item array and apply the declared function per element. This function ends up returning the 10-item array with all keys intact but the values will be null
function($v){return null; /* return ''; // if you prefer and empty string instead of null*/}, // set each value of the 10-item array to null
range( // create an 10-item array with indexes and values of 0-9
0,
max(array_keys($export_data)) // get the highest key of your array which is 9
)
),
$export_data // your original array with gaps
);
var_dump($export_data);
print_r($export_data);
if i understand correctly, you want to put free columns between data, so the keys match column number.
$arr = array(
0 => 1,
1 => 2,
2 => 3,
3 => 4,
4 => 5,
8 => 9,
9 => 10,
);
$csvArray = array();
$maxKey = max(array_keys($arr));
for($i = 0; $i <= $maxKey; $i++){
if(array_key_exists($i, $arr)){
$csvArray[$i] = $arr[$i];
} else {
$csvArray[$i] = null;
}
}
print_r($csvArray);
demo here: live demo
to describe it, just cycle through array and check wether key is set, if is, assing its value to the next array, if is not, assign null
Optimized:
$csvArray = array();
$maxKey = max(array_keys($arr));
// ++$i is microscopically faster when going for the long haul; such as 10,000,000 iterations
// Try it for yourself:
// $start = microtime(true);
// for($i=0; $i<10000000; $i++){}
// echo (microtime(true) - $start).' seconds';
for($i = 0; $i <= $maxKey; ++$i){
// we can use isset() because it returns false if the value is null anyways. It is much faster than array_key_exists()
$csvArray[$i] = (isset($arr[$i]) ? $arr[$i] : null);
}
I would just fill the array completely with empty values for the empty columns:
$export_data = array (
[0] => 1,
[1] => 2,
[2] => 3,
[3] => 4,
[4] => 5,
[5] => '',
[6] => '',
[7] => '',
[8] => 9,
[9] => 10,
);
Without the indexes (because they are automatic in any case):
$export_data = array (
1,
2,
3,
4,
5,
'',
'',
'',
9,
10,
);

Sum every last value with all previous values in array

I have an array of some values which I need to convert to new array and sum every value with all previous values. For example (array length, keys and values always differ), this is what I have:
Array
(
[0] => 1
[1] => 1
[2] => 5
[3] => 1
[4] => 1
[7] => 1
[8] => 3
[9] => 1
)
and this is what I need:
Array
(
[0] => 1
[1] => 2
[2] => 7
[3] => 8
[4] => 9
[7] => 10
[8] => 13
[9] => 14
)
I tried many different ways but always stuck at something or realized that I'm wrong somewhere. I have a feeling that I'm trying to reinvent a wheel here, because I think there have to be some simple function for this, but had no luck with finding solution. This is last way I tried:
$array = array( "0"=> 1, "1"=> 1, "2"=> 5, "3"=> 1, "4"=> 1, "7"=> 1, "8"=> 3, "9"=> 1 );
$this = current($array);
$next = next($array);
$end = next(end($array));
$sum = 0;
$newArray = array();
foreach ($array as $val){
if($val != $end){
$sum = ($this += $next);
array_push($newArray, $sum);
}
}
print_r($newArray);
..unfortunately wrong again. I spend lot of time finding ways how not to get where I need to be, can someone kick me into right direction, please?
Suggest you to use array_slice() & array_sum()
$array = array( "0"=>1,"1"=>1,"2"=>5,"3"=>1,"4"=>1,"7"=>1,"8"=>3,"9"=>1);
$keys = array_keys($array);
$array = array_values($array);
$newArr = array();
foreach ($array as $key=>$val) {
$newArr[] = array_sum(array_slice($array, 0, $key+1));
}
$newArr = array_combine($keys, $newArr);
print '<pre>';
print_r($newArr);
print '</pre>';
Output:
Array
(
[0] => 1
[1] => 2
[2] => 7
[3] => 8
[4] => 9
[7] => 10
[8] => 13
[9] => 14
)
Reference:
array_slice()
array_sum()
array_combine()
array_keys()
let assume your array variable is $a;
You can use simple for loop
for($i=1;$i<sizeof($a);$i++)
{
$a[$i]=$a[$i]+$a[$i-1];
}
You can just go over the array sum and add to a new array (in a simple way):
$array = array( "0"=> 1, "1"=> 1, "2"=> 5, "3"=> 1, "4"=> 1, "7"=> 1, "8"=> 3, "9"=> 1 );
var_dump($array);
$newArray = array();
$sum = 0;
foreach ($array as $a){
$sum += $a;
$newArray[]=$sum;
}
var_dump($newArray);
$sums = array_reduce($array, function (array $sums, $num) {
return array_merge($sums, [end($sums) + $num]);
}, []);
In other words, this iterates over the array (array_reduce) and in each iteration appends (array_merge) a number to a new array ($sums) which is the sum of the previous item in the array (end($sums)) and the current number. Uses PHP 5.4+ array syntax ([]).
You complicated too much. Loop trough all elements of array and add current element to sum. Then assign that sum to new array.
$array = array( "0"=> 1, "1"=> 1, "2"=> 5, "3"=> 1, "4"=> 1, "7"=> 1, "8"=> 3, "9"=> 1 );
$sum = 0;
$newArray = array();
foreach ($array as $key=>$val){
$sum += $val;
$newArray[$key]=$sum;
}
Make sure to get indexes right.

PHP - split array by key

I've got the following array, containing ordered but non consecutive numerical keys:
Array
(
[4] => 2
[5] => 3
[6] => 1
[7] => 2
[8] => 1
[9] => 1
[10] => 1
)
I need to split the array into 2 arrays, the first array containing the keys below 5, and the other array consisting of the keys 5 and above. Please note that the keys may vary (e.g. 1,3,5,10), therefore I cannot use array_slice since I don't know the offset.
Do you know any simple function to accomplish this, without the need of using a foreach ?
Just found out array_slice has a preserve_keys parameter.
$a = [
4 => 2,
5 => 3,
6 => 1,
7 => 2,
8 => 1,
9 => 1,
10 => 1
];
$desired_slice_key = 5;
$slice_position = array_search($desired_slice_key, array_keys($a));
$a1 = array_slice($a, 0, $slice_position, true);
$a2 = array_slice($a, $slice_position, count($a), true);
you could use array_walk, passing in the arrays you wish to add the keys to by reference using the use keyword - something along the lines of this should work:
$splitArray = [1 => 2, 3 => 1, 5 => 2, 7 => 1, 9 => 3, 10 => 1];
$lt5 = [];
$gt5 = [];
array_walk($splitArray, function(&$val, $key) use (&$lt5, &$gt5) {
$key < 5 ? $lt5[] = $key : $gt5[] = $key;
});
var_dump($lt5, $gt5);

Undefined offset with count()

I have an array $MyArray which has some elements which are also array (lets call them subarrays). I want to know how many elements the subarray with the most elements has. The problem is, that I don't know if the index exists:
max(
#count($MyArray[$i*7]),
#count($MyArray[$i*7+1]),
#count($MyArray[$i*7+2]),
#count($MyArray[$i*7+3]),
#count($MyArray[$i*7+4]),
#count($MyArray[$i*7+5]),
#count($MyArray[$i*7+6])
);
Struckture of $MyArray:
Array(
12 => array (
0 => array ( 0 => 0, 1 => 1, ),
1 => array ( 0 => 13, 1 => 1, ),
2 => array ( 0 => 15, 1 => 1, ),
3 => array ( 0 => 20, 1 => 1, ),
4 => array ( 0 => 69, 1 => 1, )
),
5 => array (
0 => array ( 0 => 55, 1 => 1, ),
1 => array ( 0 => 32, 1 => 1, ),
2 => array ( 0 => 12, 1 => 1, ),
3 => array ( 0 => 21, 1 => 5, )
),
....
)
Can this be done better (faster)?
edit: I know foreach and I don't want to loop over every element in this array. I just want an interval of it. # is used, because I don't know if $MyArray[$i*7 + x] is Null or an array.
$i is a element of [0, 1, 2, 3, 4] (sometimes also 5)
$biggest = 0;
foreach ($MyArray as $value) {
if ($biggest < count($value)) {
$biggest = count($value);
}
}
I see, you want the size of the biggest array in the array, correct?
Simple and old school approach:
<?php
$max = -1;
foreach($MyArray as $subarray)
{
$items = count($subarray);
if($items > $max)
$max = $items;
}
echo $max;
?>
This works best since you only want to know how many elements the subarray with the most elements has.
$max = 0;
foreach ($MyArray as $value) {
$max = max($max,count($value));
}
Try this:
$arr = array();
for ($j=0;$j<=6;$j++) {
if (isset($MyArray[$i*7+$j])) $arr[] = count($MyArray[$i*7+$j]);
}
$result = max($arr);
I don't know exactly what $i refers to though...
// get the interesting part of the array
$chunk = array_intersect_key($input_array, array_flip(range($i*7, $i*7+6)));
// max(count)
$max = $chunk ? max(array_map('count', $chunk)) : 0;

Categories