Php Array sorting assoc key after intersect key - php

Currently I have this:
$pattern = array('industry_id','category_id','subcategory_id');
$data = array('advert_id' => string '261501' (length=6)
'advert_type_id' => string '7' (length=1)
'user_id' => string '6221' (length=4)
'industry_id' => string '17' (length=2)
'category_id' => string '769' (length=3)
'subcategory_id' => string '868' (length=3)
'model' => string 'Custom Semi Drop Deck Trailer' (length=29)
'description' => string 'Industry: Trailer );
Then:
array_intersect_key( $data , array_flip($pattern) );
Using array_interect_key & array_flip to get the values from $data based on $pattern, I will get a result like this:
array (size=3)
'category_id' => string '769' (length=3)
'subcategory_id' => string '930' (length=3)
'industry_id' => string '17' (length=2)
Unfortunately as you can see the result key sorting is not the same that I declared in $pattern. Is there a shorthand way to sort it like I declared in $pattern because after this I want to implode the array and do something like this industry_id.category_id.subcategory_id without hard coding the keys.

Since you already figured out array_intersect_key method which will not get you the desired key ordering of $pattern, try this instead:
// since original $pattern is not ASSOC (only vals)
// flip it so defined vals become keys
$pattern_flipped = array_flip($pattern);
$result = array();
foreach ($pattern_flipped as $k => $v) {
if (isset($data[$k])) {
$result[$k] = $data[$k];
}
}
var_dump($result); // test
// can use original 0 1 2 dynamic keys for concatenation
echo $result[$pattern[0]], $result[$pattern[1]], $result[$pattern[2]], '<br>';
// or use hardcoded keys
echo $result['industry_id'], $result['category_id'], $result['subcategory_id'], '<br>';

You know I'm not sure how you're getting the result you describe. I've tried your code and I get
array (size=3)
'industry_id' => string '17' (length=2)
'category_id' => string '769' (length=3)
'subcategory_id' => string '868' (length=3)
You could do this another way though using array_filter
$newData = array_filter($data, function($key) use ($pattern) {
if (in_array($key, $pattern))
return true;
}, ARRAY_FILTER_USE_KEY)

Related

How to loop over an array and conditionally update a nested value

I have two arrays like:
array (size=4)
0 => string '5' (length=1)
1 => string '4' (length=1)
2 => string '2' (length=1)
3 => string '2' (length=1)
3 => string '8' (length=1)
and one array more that I load from an XML file:
object(SimpleXMLElement)[1]
public 'book' =>
array (size=101)
0 =>
object(SimpleXMLElement)[2]
public 'id' => string '1' (length=1)
public 'title' => string 'p' (length=1)
1 =>
object(SimpleXMLElement)[3]
public 'id' => string '2' (length=1)
public 'title' => string 'pp' (length=2)
2 =>
object(SimpleXMLElement)[4]
public 'id' => string '3' (length=1)
public 'title' => string 'pen' (length=3)
3 =>
object(SimpleXMLElement)[5]
public 'id' => string '4' (length=1)
public 'title' => string 'lapton' (length=6)
......
......
101 =>
object(SimpleXMLElement)[103]
public 'id' => string '101' (length=1)
public 'title' => string 'title' (length=5)
I want to compare each value of key id of second array with key of first array for each value. When it's the same, I want to update value of key title of second array.
Assuming your first array is $idArray and your second is $xmlArray, you could use something like this.
$result = array_map(function($xmlElement) use ($idArray) {
if (in_array($xmlElement->id, $idArray)) {
$xmlElement->title = 'updated value';
}
return $xmlElement;
}, $xmlArray);
Assumptions
the first array is called $array1
the second array is called $fromXML
the second array is not actually an array, it's a SimpleXMLElement with the following structure (psuedocode / JSONish syntax)
{
'book' => {
0 => SimpleXMLElement {
'id' => 1,
'title' => 'p'
}
}
}
I assume you can access the second array of elements with $fromXML['book']
I assume you can access an attribute of the first element with $fromXML['book'][0]['id']
I assume that you can set the text of the title of the first element with $fromXML['book'][0]['title'][0] = 'new title'
based on How can I set text value of SimpleXmlElement without using its parent? and PHP SimpleXML, how to set attributes? and PHP foreach change original array values
Solution
foreach($fromXML['book'] as $key => $element) {
if(array_key_exists($element['id'], $array1)) {
$fromXML['book'][$key]['title'][0] = $array1[$element->id];
}
}
Caveat and troubleshooting
I didn't test this, just going off of the documentation. If I've misinterpreted the structure of your SimpleXMLElement array, try experimenting with var_dump($fromXML['some']['key']) until you find the right way to access the array/element
Note: Apparently, array_key_exists() performs better than in_array() on large arrays
Try this for now
foreach($array1 as $arr1 => $val1){
foreach($array2 as $arr2 =>$val2){
if($arr1==$arr2){
$val2['title']='update value';
}
}
}

Array merge if key not exists

I tried merging two arrays if the key is not exists in the array but I cannot accomplish this. How can i do? This is what I have tried:
array (size=3) // name of the array $exchange
'purchase' => string '1' (length=1)
'agriculture' => string '1' (length=1)
array (size=6) // name of the array $fixed
'purchase' => string '0' (length=1)
'ICT' => string '0' (length=1)
'agriculture' => string '0' (length=1)
'entertainment' => string '0' (length=1)
'goods and service' => string '0' (length=1)
'other' => string '0' (length=1)
foreach($fixed as $keys=>$values){
if(!in_array($values, $exchange, true)){
array_push($exchange, $keys);
}
}
I get this result:
array (size=7)
'ICT' => string '1' (length=1)
0 => string 'purchase' (length=8)
1 => string 'ICT' (length=3)
2 => string 'agriculture' (length=11)
3 => string 'entertainment' (length=13)
4 => string 'goods and service' (length=17)
5 => string 'other' (length=5)
But I want:
array (size=7)
'ICT' => string '1' (length=1)
'purchase' => string '0' (length=8)
'agriculture' => string '0' (length=11)
'entertainment' => string '0' (length=13)
'goods and service' => string '0' (length=17)
'other' => string '0' (length=5)
Try this:
foreach ($fixed as $keys => $values) {
if (! array_key_exists($keys, $exchange)) {
$exchange[$keys] = $values;
}
}
It checks if the key $keys does not already exists in $exchange and adds it together with its value ($values).
Or you can simply replace the entire foreach() block with:
$exchange = $exchange + $fixed;
The addition $exchange + $fixed adds to $exchange the keys (and their values) that are in $fixed but are not in $exchange. The combined array is then stored in $exchange.
Read also this answer. It explains where your code is wrong.
There's a couple of problems with this:
in_array will search the values of the given array, not the keys, so in this case you just end up checking if the value "0" exists in the array $variable. I assume instead you wanted to check if the key already exists.
array_push pushes a new value into the next available key.
What you need is to check if a key exists, and if not, add it with the existing value. Try this instead:
for($fixed as $key=>$value)
{
if(!isset($exchange[$key])) // Check if the key exists
{
$exchange[$key] = $value; // Add the new key -> value pair.
}
}
Try with array_merge (http://php.net/manual/es/function.array-merge.php)
$result = array_merge($array1, $array2);
You can do it in several ways depending the result you desire:
foreach($fixed as $key=>$values){
if(!isset($exchange[$key])){
$exchange[$key]=values;
}
}
or
$exchange += $fixed;
or
$exchange = array_merge($fixed,$exchange);

multiarray - how to keep first 3 index groups of each source type

I have a multi-array where I need to keep the first 3 index groups and remove the rest from the multiarray (in each group).
See multiarray here: https://gist.github.com/no1uknow/6887497
So:
In this example I need the multi-array to keep: The first 3 Heavy, Lite, Intermediate, etc (these are identified by the source_type_cd)
Example of the Lite part of the array after the first 3 are kept:
0 =>
array (size=9)
'validated_ata' => string '25' (length=2)
'source_type_cd' => string 'Lite' (length=4)
'validated_subata' => string '22' (length=2)
'action_cd' => string '3' (length=1)
'object_cd' => string '5' (length=1)
'malfunction_cd' => string '29' (length=2)
'corrective_action_txt' => string 'Repair-Passenger Seat-Loose / Displaced' (length=39)
'rec_count' => string '00050' (length=5)
'group_id' => int 48
1 =>
array (size=9)
'validated_ata' => string '25' (length=2)
'source_type_cd' => string 'Lite' (length=4)
'validated_subata' => string '22' (length=2)
'action_cd' => string '3' (length=1)
'object_cd' => string '5' (length=1)
'malfunction_cd' => string '1' (length=1)
'corrective_action_txt' => string 'Repair-Passenger Seat-Inoperative' (length=33)
'rec_count' => string '00047' (length=5)
'group_id' => int 44
2 =>
array (size=9)
'validated_ata' => string '25' (length=2)
'source_type_cd' => string 'Lite' (length=4)
'validated_subata' => string '22' (length=2)
'action_cd' => string '3' (length=1)
'object_cd' => string '5' (length=1)
'malfunction_cd' => string '31' (length=2)
'corrective_action_txt' => string 'Repair-Passenger Seat-Worn / Chaffed / Frayed' (length=45)
'rec_count' => string '00042' (length=5)
'group_id' => int 50
You will simply have to loop through the array and look if it has any of those values and place into a new array.
Example (where $arr is your multiarray):
// My silly solution for knowing what to look for
// When one is found, it will be removed from the array.
$find = array('Lite','Lite','Lite','Intermediate','Intermediate','Intermediate','Heavy','Heavy','Heavy');
// New array where your the values you want will be placed in
$new_arr = array();
foreach($arr as $v) {
// No need to keep looking if there's no more to find.
if(empty($find))
break;
// Look in $find array if current "source_type_cd" is still sought-after
$key = array_search($v['source_type_cd'], $find);
if($key !== false) {
$new_arr[] = $v; // Add to new array
unset($find[$key]); // Remove from "find" array
}
}
Thanks Colandus I actually figured it out like this... I was trying to avoid to many loops.
In a loop above this I set the source_type_cd in an array:
$groups[]=$value['source_type_cd']
Next I loop through the array and take the top 3 of each group by using array_splice twice and then merging back into a new array.
(also, I'm using a start and end point ($group_count).)
$start = 0;
$group_count = $i+1;
$top_count = 3;
foreach($groups as $k => $v) {
$top_count_array = array_merge((array)$top_count_array, (array)array_slice(array_slice($sorted_array, $start, $group_count, true),0,$top_count,true));
$start = $start+$group_count;
}
var_dump($top_count_array);
Again appreciate the input. Tried to shorten this code down from so many loops. Also requirements will change for grabbing the amount of $top_count and $group_count... Needed something a little more dynamic. :-)

Reduce an array to just the 'named' keys

I would like a hint or much better a solution for this:
I do a regular expresion match to an url for example '/product/100/'
preg_match('/^\/(?<name>\w+)\/(?<digit>\d+)\/$/', '/product/100/', $matches);
As result of this I get the following array on $matches:
array
0 => string '/product/100/' (length=13)
'name' => string 'product' (length=7)
1 => string 'product' (length=7)
'digit' => string '100' (length=3)
2 => string '100' (length=3)
How can I use reduce this array to get this?
array
'name' => string 'product' (length=7)
'digit' => string '100' (length=3)
After I get the matching expresions, I call a function and give the 'named' keys as arguments to the function.
call_user_func_array($view, $just_named_args_no_integer_keys);
I hope anyone can give me any hint.
Best Regards
Just run the keys you get from array_keys() through array_filter():
/* This is for PHP 5.3, I'm sure you'll figure out how to the same thing pre 5.3 :) */
$allKeys = array_keys($view);
$namedKeys = array_filter($allKeys, function($value) { return !is_numeric($value); });
Update
Did not read the question properly. In this case, actually just foreach over the data:
$namedValues = array();
foreach ($view as $key => $value)
if (!is_numeric($key))
$namedValues[$key] = $value;

what's wrong with this php code?

Ok, the idea here is to have code that will append SF_ to all key names in an array.
I took my array (which is part of an object), flipped it, added the SF_, and flipped it back.
Somewhere in the process I lost some fields...
here's what I started with:
object(stdClass)[12]
public 'Affiliate_Code__c' => string 'XX-TXUJC3' (length=9)
public 'AltEmail__c' => string 'benny#oxpublishing.com' (length=22)
public 'City' => string 'Mobile' (length=6)
public 'Email' => string 'benny#oxpublishing.com' (length=22)
public 'Fax__c' => string '251-300-1234' (length=12)
public 'FirstName' => string 'Benny' (length=5)
public 'LastName' => string 'Butler' (length=6)
public 'Phone' => string '251-300-3530' (length=12)
public 'PostalCode' => string '36606' (length=5)
public 'State' => string 'AL' (length=2)
public 'Street' => string '851 E I-65 Service Rd' (length=21)
public 'test1__c' => float 1
array
'SF_Affiliate_Code__c' => string 'XX-TXUJC3' (length=9)
'SF_Email' => string 'benny#oxpublishing.com' (length=22)
'SF_City' => string 'Mobile' (length=6)
'SF_Fax__c' => string '251-300-1234' (length=12)
'SF_FirstName' => string 'Benny' (length=5)
'SF_LastName' => string 'Butler' (length=6)
'SF_Phone' => string '251-300-3530' (length=12)
'SF_PostalCode' => int 36606
'SF_State' => string 'AL' (length=2)
'SF_Street' => string '851 E I-65 Service Rd' (length=21)
And here's my code:
$response = $mySforceConnection->query(($query));
foreach ($response->records as $SF) {
}
var_dump($SF);
$SF = array_flip($SF);
foreach ($SF as $key => $value){
$SF[$key] = 'SF_'.$value;
}
$SF = array_flip($SF);
echo "<pre>";
var_dump($SF);
echo "</pre>";
extract($SF);
Any idea?
I'm new to OO programming of any sort, and I'm sure this has something to do with it.
I'm so stupid I have to do:
foreach ($response->records as $SF) { }
because I don't know how to get to that array any other way.
Help!
Thanks!
When you do the flip, you end up with duplicate keys - the values become the keys, and your values are not unique (e.g. Email and AltEmail__c both have the same value).
Rather than doing a flip then flipping back, just create a new array and copy the values in with the new keys:
$SF_new = array();
foreach($SF as $key => $value ) {
$SF_new['SF_' . $key] = $value;
}
// And if you want to continue using the $SF name...
$SF = $SF_new;
array_flip will flip the values and keys, as you said. A PHP array cannot have multiple keys with the same name. Try something like this to avoid flipping:
<?php
$SF = array();
foreach($response->records as $key => $value)
{
$SF['SF_' . $key] = $value;
}
About the way you get to the array in the object, this is the proper way to do it.
$SF = get_object_vars($response);
Will transform your object into an array.
flip swaps keys and values. because you have values that share the same value, you lose them in the flip.

Categories