Best way around combine_array with identical keys? - php

I was using combine_array to update a MySQL table from a CSV file. I thought everything was working like a champ, but it turns out the data source isn't amazing. There are multiple columns with the same name and those columns become the keys in an array. Example take the two arrays:
array 1
[0]=>"name"
[1]=>"email"
[2]=>"shoe size"
[3]=>"email"
array 2
[0]=>"Jake Doe"
[1]=>"jake#example.mail"
[2]=>"10.5"
[3]=>""
if I was to use array_combine($array1,$array2) I would get:
["name"]=>"Jake Doe"
["email"]=>""
["shoe size"]=>"10.5"
The problem is that I'd obviously prefer to have the email not get overwritten by a blank value. What I can up with is the function below. What I'm looking for is just a second set of eyes. Is this there a better way to do this? I hate that I have two nested ifs, but I'm not sure how I'd go about making it cleaner or if that's even possible.
//array_combine simply overwrites repeat keys, this only overwrites if the value is empty
//if the first instance of the key has a value, it ignores duplicate keys
function new_array_combine($key_array,$value_array){
foreach($value_array as $key=>$value){
if(array_key_exists($key_array[$key],$new_array)){
if(empty($new_array[$key_array[$key]]))$new_array[$key_array[$key]]=$value;
}else{
$new_array[$key_array[$key]]=$value;
}
}
return $new_array;
}

The only problem I see with your program is when key names do not match in each array
array 1
[0]=>"name"
[1]=>"email"
[2]=>"shoe size"
[3]=>"email"
array 2
[0]=>"Jake Doe"
[1]=>"jake#example.mail"
[3]=>"10.5"
[4]=>""
Suggested modifications:
function new_array_combine($a1, $a2){
$result=Array();
reset($a1);
foreach($a2 as &$v){
$key=current($a1);
if (!isset($result[$key])||empty($result[$key]))
$result[$key]=$v;
next($a1);
}
return $result;
}

Blah. Trying to rescue this response, since my first obviously missed the entire point of the post.
If you're only worried about those blank values, then I would say you could walk the arrays once through first, 'cleaning' them by deleting indexes with no corresponding value:
<?php
// $a and $b as defined in the example
foreach($a as $k => $v) {
if(empty($b[$k])) {
unset($a[$k]);
unset($b[$k]);
}
}
$c = array_combine($a, $b);
print_r($c);
Output:
Array(
[name] => Jake Doe
[email] => jake#example.mail
[shoesize] => 10.5
)
Edit: To include blank values (but still not let blanks override existing values), first get the unique keys from $a and use it to build an empty result array, then just skip blank values while looping through...
<?php
// $a and $b as defined in the example
$result = array();
$keys = array_unique($a);
foreach($keys as $key) $result[$key] = '';
foreach($a as $k => $v) {
if(empty($b[$k])) continue;
$result[$v] = $b[$k];
}
print_r($result);
Output:
Array(
[name] => Jake Doe
[email] => jake#example.mail
[shoesize] => 10.5
)

Related

Multidimensional array keys to variable

sadly i havent found any solution yet.
I have an multidimensional array which looks like this:
Array
(
[0] => Array
(
[Symbol] => CASY.US
[Position] => 169873920
)
[1] => Array
(
[Symbol] => US500
[Position] => 168037428
) )
Now i want to write the name of the keys of the inner array into variables so that i have these variables with the values:
$col1 = "Symbol"
$col2 = "Position"
How can i achieve that? Somehow with a couple of foreach loops?
Background: After that i want to check if the columns have the right name for a validation.
Thanks in advance!
Loop nested and save the keys to an array with "col" and an integer that you later can (if you really must extract), but I recommend to keep them in the array.
foreach($array as $subarray){
$i = 1;
foreach($subarray as $key => $val){
$keys["col" . $i] = $key;
$i++;
}
break; // no need to keep looping if the array is uniform
}
//if you must:
extract($keys);
https://3v4l.org/ALVtp
If the subarrays are not the same then you need to loop all subarrays and see if the key has already been saved, if not save it else skip it.
$keys =[];
$i = 1;
foreach($array as $subarray){
foreach($subarray as $key => $val){
if(!in_array($key, $keys)){
$keys["col" . $i] = $key;
$i++;
}
}
}
var_dump($keys);
//if you must:
extract($keys);
var_dump($col1, $col2, $col3);
https://3v4l.org/EklPK
Honestly I would do something like this:
$required = array_flip(['Symbol', 'Position']); //flip because I am lazy like that ['Symbol'=>0, 'Position'=>1]
foreach($array as $subarray){
$diff = array_diff_key($required, $subarray);
//prints any keys in $required that are not in $subarray
print_r($diff);
if(!empty($diff)){
//some required keys were missed
}
}
While its not clear how you validate these the reason is as I explained in this comment
it still doesn't solve the problem, as you really have no way to know what the keys will be (if they are not uniform). So with my example foo is $col3 what if I have bar later that's $col4 what if the order is different next time.... they will be different numbers. Sure it's a few what if's but you have no guarantees here.
By dynamically numbering the keys, if the structure of the array ever changes you would have no idea what those dynamic variables contain, and as such no idea how to validate them.
So even if you manage to make this work, if your data ever changes you going to have to re-visit the code.
In any case if your wanting to see if each array contains the keys it needs to, what I put above would be a more sane way to do it.

PHP | Array get both value and key

I have a PHP array that looks like that:
$array = Array
(
[teamA] => Array
(
[188555] => 1
)
[teamB] => Array
(
[188560] => 0
)
[status] => Array
(
[0] => on
)
)
In the above example I can use the following code:
echo $array[teamA][188555];
to get the value 1.
The question now, is there a way to get the 188555 in similar way;
The keys teamA, teamB and status are always the same in the array. Alse both teamA and teamB arrays hold always only one record.
So is there a way to get only the key of the first element of the array teamA and teamB?
More simple:
echo key($array['teamA']);
More info
foreach($array as $key=>$value)
{
foreach($value as $k=>$v)
{
echo $k;
}
}
OR use key
echo key($array['teamA']);
echo array_keys($array['teamA'])[0];
Refer this for detailed information from official PHP site.
Use two foreach
foreach($array as $key => $value){
foreach($value as $key1 => $value2){
echo $key1;
}
}
This way, you can scale your application for future use also. If there will be more elements then also it would not break application.
You can use array_flip to exchange keys and values. So array('12345' => 'foo') becomes array('foo' => '12345').
Details about array_flip can be studied here.
I would suggest using list($key, $value) = each($array['teamA']) since the question was for both key and value. You won't be able to get the second or third value of the array without a loop though. You may have to reset the array first if you have changed its iterator in some way.
I suppose the simplest way to do this would be to use array_keys()?
So you'd do:
$teamAKey = array_shift(array_keys($array['TeamA']));
$teamBKey = array_shift(array_keys($array['TeamB']));
Obviously your approach would depend on how many times you intend to do it.
More info about array_keys and array_shift.

PHP push values into associative array

I can't find an answer to this anywhere.
foreach ($multiarr as $array) {
foreach ($array as $key=>$val) {
$newarray[$key] = $val;
}
}
say $key has duplicate names, so when I am trying to push into $newarray it actually looks like this:
$newarray['Fruit'] = 'Apples';
$newarray['Fruit'] = 'Bananas';
$newarray['Fruit'] = 'Oranges';
The problem is, the above example just replaces the old value, instead of pushing into it.
Is it possible to push values like this?
Yes, notice the new pair of square brackets:
foreach ($multiarr as $array) {
foreach ($array as $key=>$val) {
$newarray[$key][] = $val;
}
}
You may also use array_push(), introducing a bit of overhead, but I'd stick with the shorthand most of the time.
I'll offer an alternative to moonwave99's answer and explain how it is subtly different.
The following technique unpacks the indexed array of associative arrays and serves each subarray as a separate parameter to array_merge_recursive() which performs the merging "magic".
Code: (Demo)
$multiarr = [
['Fruit' => 'Apples'],
['Fruit' => 'Bananas'],
['Fruit' => 'Oranges'],
['Veg' => 'Carrot'],
//['Veg' => 'Leek'],
];
var_export(
array_merge_recursive(...$multiarr)
);
As you recursively merge, if there is only one value for a respective key, then a subarray is not used, if there are multiple values for a key, then a subarray is used.
See this action by uncommenting the Leek element.
p.s. If you know that you are only targetting a single column of data and you know the key that you are targetting, then array_column() would be a wise choice.
Code: (Demo)
var_export(
['Fruit' => array_column($multiarr, 'Fruit')]
);

PHP search array using wildcard?

Assume that i have the following arrays containing:
Array (
[0] => 099/3274-6974
[1] => 099/12-365898
[2] => 001/323-9139
[3] => 002/3274-6974
[4] => 000/3623-8888
[5] => 001/323-9139
[6] => www.somesite.com
)
Where:
Values that starts with 000/, 002/ and 001/ represents mobile (cell) phone numbers
Values that starts with 099/ represents telephone (fixed) numbers
Vales that starts with www. represents web sites
I need to convert given array into 3 new arrays, each containing proper information, like arrayTelephone, arrayMobile, arraySite.
Function in_array works only if i know whole value of key in the given array, which is not my case.
Create the three empty arrays, loop through the source array with foreach, inspect each value (regexp is nice for this) and add the items to their respective arrays.
Loop through all the items and sort them into the appropriate arrays based on the first 4 characters.
$arrayTelephone = array();
$arrayMobile = array();
$arraySite = array();
foreach($data as $item) {
switch(substr($item, 0, 4)) {
case '000/':
case '001/':
case '002/':
$arrayMobile[] = $item;
break;
case '099/':
$arrayTelephone[] = $item;
break;
case 'www.':
$arraySite[] = $item;
break;
}
}
You can loop over the array and push the value to the correct new array based on your criteria. Example:
<?php
$fixed_array = array();
foreach ($data_array as $data) {
if (strpos($data, '099') === 0) {
$fixed_array[] = $data;
}
if ....
}
Yes i actually wrote the full code with preg_match but after reading some comments i accept that its better to show the way.
You will create three different arrays named arrayTelephone, arrayMobile, arraySite.
than you will search though your first array with foreach or for loop. Compare your current loop value with your criteria and push the value to one of the convenient new arrays (arrayTelephone, arrayMobile, arraySite) after pushing just continue your loop with "continue" statement.
You can find the solution by looking add the Perfect PHP Guide

Change the array KEY to a value from sub array

This is the set of result from my database
print_r($plan);
Array
(
[0] => Array
(
[id] => 2
[subscr_unit] => D
[subscr_period] =>
[subscr_fee] =>
)
[1] => Array
(
[id] => 3
[subscr_unit] => M,Y
[subscr_period] => 1,1
[subscr_fee] => 90,1000
)
[2] => Array
(
[id] => 32
[subscr_unit] => M,Y
[subscr_period] => 1,1
[subscr_fee] => 150,1500
)
)
How can I change the $plan[0] to $plan[value_of_id]
Thank You.
This won't do it in-place, but:
$new_plan = array();
foreach ($plan as $item)
{
$new_plan[$item['id']] = $item;
}
This may be a bit late but I've been looking for a solution to the same problem. But since all of the other answers involve loops and are too complicated imho, I've been trying some stuff myself.
The outcome
$items = array_combine(array_column($items, 'id'), $items);
It's as simple as that.
You could also use array_reduce which is generally used for, well, reducing an array. That said it can be used to achieve an array format like you want by simple returning the same items as in the input array but with the required keys.
// Note: Uses anonymous function syntax only available as of PHP 5.3.0
// Could use create_function() or callback to a named function
$plan = array_reduce($plan, function($reduced, $current) {
$reduced[$current['id']] = $current;
return $reduced;
});
Note however, if the paragraph above did not make it clear, this approach is overkill for your individual requirements as outlined in the question. It might prove useful however to readers looking to do a little more with the array than simply changing the keys.
Seeing the code you used to assemble $plan would be helpful, but I'm going assume it was something like this
while ($line = $RES->fetch_assoc()) {
$plan[] = $line;
}
You can simply assign an explicit value while pulling the data from your database, like this:
while ($line = $RES->fetch_assoc()) {
$plan[$line['id']] = $line;
}
This is assuming $RES is the result set from your database query.
In my opinion, there is no simpler or more expressive technique than array_column() with a null second parameter. The null parameter informs the function to retain all elements in each subarray, the new 1st level keys are derived from the column nominated in the third parameter of array_column().
Code: (Demo)
$plan = array_column($plan, null, 'id');
Note: this technique is also commonly used to ensure that all subarrays contain a unique value within the parent array. This occurs because arrays may not contain duplicate keys on the same level. Consequently, if a duplicate value occurs while using array_column(), then previous subarrays will be overwritten by each subsequent occurrence of the same value to be used as the new key.
Demonstration of "data loss" due to new key collision.
$plans = array();
foreach($plan as $item)
{
$plans[$item['id']] = $item;
}
$plans contains the associative array.
This is just a simple solution.
$newplan = array();
foreach($plan as $value) {
$id = $value["id"];
unset($value["id"]);
$newplan[$id] = $value;
}

Categories