Using PHP to "multiply" array values - php

Apologies in advance since I'm a PHP novice and I'm sure I'm not using the right terms here.
I am making an automated product data feed using a set of provided SKUs, but the feed requires separate entries for size and gender variation of the products.
Is there a simple way to take this:
$SKUs = array('Product1', 'Product2', 'Product3')
And "multiply" each entry in the array with these:
$gender = array('M', 'F');
$size = array('S', 'M', 'L', 'XL');
So that I end up with this result:
$feed = array('Product1M-S', 'Product1M-M', 'Product1M-L', 'Product1M-XL', 'Product1F-S'...)

$feed = array();
foreach ($SKUs as $sku) {
foreach ($gender as $g) {
foreach ($size as $s) {
$feed[] = $sku.$g.'-'.$s;
}
}
}
print_r($feed);
Maybe there exists a simple array function, but this one is easy to read, and ready for future "easy" changes.
PS. This is a great lecture with a similar problem: http://dannyherran.com/2011/06/finding-unique-array-combinations-with-php-permutations/
PS2. As KA_lin suggested, you can make a function to do this, however, I haven't got knowledge about the array and product structure, and don't know if i.e. the sizes are always the same (S, L, X) for each product. If the arrays are always the same, they can be hardcoded inside the function body as KA_lin suggested. I presented only a linear solution, but You can easily upgrade it too Your needs.

You just have to iterate through all 3 arrays at once and append to a new array like this:
$SKUs = array('Product1', 'Product2', 'Product3')
function generate_product_combinations($SKUs)
{
$size = array('S', 'M', 'L', 'XL');//these 2 arrays are universal
$gender = array('M', 'F'); //and can belong here rather than params
$final = array(); //but should be taken from a config
foreach($SKUs as $sku)
{
foreach($size as $size_shirt)
{
foreach($gender as $sex)
{
$final[]=$sku.$gender.'-'.$sex;
}
}
}
return $final;
}
$products = generate_product_combinations($SKUs);

Related

Multidimensional arrays in PHP - how to add values using foreach

I have a multidimensional array defined as follows
$SquadList = array('name', 'position', 'dob', 'nation', 'games', 'goals', 'assists');
I'm looping through several foreach loops and storing data from JSON
foreach ($season as $key => $squad){
$SquadList[0] = $squad['full_name'];
$SquadList[1] = $squad['position'];
$SquadList[2] = gmdate("d-m-y", $birthday);
$SquadList[3] = $squad['nationality'];
$SquadList[4] = $squad['appearances_overall'];
$SquadList[5] = $squad['goals_overall'];
$SquadList[6] = $squad['assists_overall']; }
foreach ($season1 as $key => $squad){
$SquadList[0] = $squad['full_name'];
$SquadList[1] = $squad['position'];
$SquadList[2] = gmdate("d-m-y", $birthday);
$SquadList[3] = $squad['nationality'];
$SquadList[4] = $squad['appearances_overall'];
$SquadList[5] = $squad['goals_overall'];
$SquadList[6] = $squad['assists_overall'];
The code is messy. The output is only 2 elements when it should be 30+
I've tried array_push as follows
array_push($SquadList['name'], $squad['full_name'];
i'm not sure if i get the question correctly, but i imagine you want it to be structured something like this:
$SquadList = []; // define it as an array
$ctr = 0; // define a counter that would be used in the two iterations
foreach ($season as $key => $squad){
$SquadList[$ctr][0] = $squad['full_name'];
$SquadList[$ctr][1] = $squad['position'];
$SquadList[$ctr][2] = gmdate("d-m-y", $birthday);
$SquadList[$ctr][3] = $squad['nationality'];
$SquadList[$ctr][4] = $squad['appearances_overall'];
$SquadList[$ctr][5] = $squad['goals_overall'];
$SquadList[$ctr][6] = $squad['assists_overall'];
$ctr++; // increase counter
}
foreach ($season1 as $key => $squad){
$SquadList[$ctr][0] = $squad['full_name'];
$SquadList[$ctr][1] = $squad['position'];
$SquadList[$ctr][2] = gmdate("d-m-y", $birthday);
$SquadList[$ctr][3] = $squad['nationality'];
$SquadList[$ctr][4] = $squad['appearances_overall'];
$SquadList[$ctr][5] = $squad['goals_overall'];
$SquadList[$ctr][6] = $squad['assists_overall'];
$ctr++; // increase counter
}
The reason you had two results is because you got the last squad for each season. This happened because each time a season iterated, it overwrote the previous squad.
To solve this problem, $SquadList must be an array. But you have to assign all its members at once, otherwise the array will increment every time you add a member.
Populating an array of arrays
foreach ($season as $key => $squad) {
$squadList[] = [
$squad['full_name'],
$squad['position'],
gmdate("d-m-y", $squad['birthday']),
$squad['nationality'],
$squad['appearances_overall'],
$squad['goals_overall'],
$squad['assists_overall']
];
}
Note a couple of changes I made:
I removed the capitalization on $squadList because convention has starting with a capital indicating an object, not a plain old variable
$birthday was undefined, so I made an educated guess
Cleaning up the code
You mentioned that “the code is messy”. That is a very healthy observation to make.
What you are noticing is the result of two things:
Your code is repeating itself (a violation of DRY - Don’t Repeat Yourself)
Need to follow convention of PSR-12
So let’s get rid of the code duplication
Refactoring
When you start repeating yourself, that’s a signal to pull things into a function
function buildSquad(array $season)
{
foreach ($season as $key => $squad) {
$squadList[] = [
$squad['full_name'],
$squad['position'],
gmdate("d-m-y", $squad['birthday']),
$squad['nationality'],
$squad['appearances_overall'],
$squad['goals_overall'],
$squad['assists_overall']
];
}
return $squadList;
}
$squadList = [];
// if you just want to lump them all together
$squadList[] = buildSquad($season);
$squadList[] = buildSquad($season2);
// etc

How to map array depth?

I'm not sure how to call this, and I can't find what I'm looking for because I must be looking for the wrong keywords, so even the right search term would help me out here:
I have a $map array and a $data array. The $data array is a dynamic array based on a xml that is parsed. Simplified Example:
$data = array('a' => array(0=> array('hello'=>'I want this data')));
$map = array('something' => 'a.0.hello');
Now I'd like to set $test to the value of $data['a']['0']['hello'] by somehow navigating there using $map['something']. The idea behind this is to create a mapping array so that no code changes are required if the xml format is to be changed, only the mapping array. Any help in the good direction is very much appreciated :)
// Set pointer at top of the array
$path = &$data;
// Asume that path is joined by points
foreach (explode('.', $map['something']) as $p)
// Make a next step
$path = &$path[$p];
echo $path; // I want this data
There's not really a good way to programmatically access nested keys in arrays in PHP (or any other language I can think of, actually).
function getDeepValue(&$arr, $keys) {
if (count($keys) === 0)
return $arr;
else
return getDeepValue($arr[$keys[0]], array_slice($keys, 1));
}
$data = ['a' => [0=> ['hello'=>'I want this data']]];
$map = ['something' => getDeepValue($data, ['a', '0', 'hello'])];
var_dump($map);
// array(1) {
// ["something"]=>
// string(16) "I want this data"
// }
If you want to use the string of keys, just use
getDeepValue($arr, explode('.', 'a.0.hello'))
If that's a common operation you have to do, you could add another layer of abstraction that accepts string-based lookup of deep values.

Reorder an array from it's default order

I have an array that comes in this way since it's generated this way, and it's a heck of a task to change the way it's generated. This is part of it, there loads more.
$name['Age'] = '25';
$name['Location'] = 'Seattle';
$name['Last'] = 'Gates';
$name['First'] = 'Bill';
print_r($name);
How can I change it's order to something like below once it's generated?
$name['First'] = 'Bill';
$name['Last'] = 'Gates';
$name['Age'] = '25';
$name['Location'] = 'Seattle';
print_r($name);
Yes, there's a function that lets you reorder the associative array by keys according to your own criteria. It's called uksort:
$key_order = array_flip(['First', 'Last', 'Age', 'Location']);
uksort($name, function($key1, $key2) {
return $key_order[$key1] - $key_order[$key2];
});
print_r($name);
Demo.
Having said all that, I can't help wondering ain't you need something different instead: changing the order of output of your array only. For example:
$output_order = ['First', 'Last', 'Age', 'Location'];
foreach ($output_order as $key) {
echo $key, ' => ', $name[$key], PHP_EOL;
}

Select value out of array in PHP

Ok, so I have this in a JSON array (the output of retrievedData())
{
"device": {
"01AA02AB141208VV": {
"$version": -148598935,
"$timestamp": 1344382016000,
"serial_number": "01AA02AB141208VV"
}
}
}
However, I can't seem to select the serial number. I have tried what usually works, but I can't select it. This is assuming we don't already know the "01AA02AB141208VV".
$retrieved_data = retrieveData($array['userid'], $array['urls']['transport_url'], $array['access_token']);
$retrieved_data_array = json_decode($retrieved_data, true);
$serial_number = $retrieved_data_array['device'][0]['serial_number'];
Am I doing something wrong? I bet it's really simple, but I just cannot figure it out!
Thanks!
Unfortunately, it's not really simple. You're trying to find 42 Main St. when you don't know the city Main St. is located in. The only way to find the serial_number would be to loop over $retrieved_data_array with foreach until you find the value you want.
you can use key() function to access the keys of the associative array (in this case the '$retrieved_data_array['device']' array:
<?php
$data = '{"device": {"01AA02AB141208VV": {"$version": -148598935,"$timestamp": 1344382016000,"serial_number": "01AA02AB141208VV"}}}';
$retrieved_data_array = json_decode($data, true);
$serial_number = key($retrieved_data_array['device']);
reset($retrieved_data_array['device']);
print_r($serial_number);
print_r($retrieved_data_array['device'][$serial_number]);
?>
This will grab the serial numbers, assuming you have multiple items in the devices array:
$keys = array();
foreach( $retrieved_data_array['device'] as $key => $val ){
$keys[] = $key;
}
$serial = $keys[0];
This can be reduced if you know you only have one item in the array...

Removing php array duplicates with regard to a few specific indexes

Suppose I have a multi-dimensional array with 100's of sub-arrays. The sub-arrays always have at least 3 indexes, but can have more. I'd like to remove from the big array all the sub-arrays which are duplicates of others in regards to those three indexes. Example with an array that only has two sub-arrays:
array(array(0 => 'a', 1=> 'b', 2 => 'c', 3 => 'd'), array(0 => 'a', 1=> 'b', 2=> 'c', 3=> 'z'))
one of the sub-arrays would be removed, because the first 3 indexes match even though the 4th does not.
I'm looking for the most elegant/efficient solution.
/**
* Create Unique Arrays using an md5 hash
*
* #param array $array
* #return array
*/
function arrayUnique($array, $preserveKeys = false)
{
$arrayRewrite = array();
$arrayHashes = array();
foreach($array as $key => $item) {
$hash = md5(serialize($item));
if (!isset($arrayHashes[$hash])) {
$arrayHashes[$hash] = $hash;
if ($preserveKeys) {
$arrayRewrite[$key] = $item;
} else {
$arrayRewrite[] = $item;
}
}
}
return $arrayRewrite;
}
$uniqueArray = arrayUnique($array);
var_dump($uniqueArray);
FROM: http://www.phpdevblog.net/2009/01/using-array-unique-with-multidimensional-arrays.html
Removed comments to give people incentive to visit site - I've used this on a few occasions.
Hope that helps!
EDIT: although not a solution to this particular problem in that you require matching the first 3 indexes, it is still nontheless a very good solution to the general question: how do I use array_unique() on a multidimensional array.
If somebody could pop along and edit for your purposes, all the better!
Zenph gets it 90% right, but he wanted to only look at the first 3 elements as unique. You can use the function below in conjunction with Zenph's code right before the serialize to only look at the first three elements.
function firstThree($array)
{
$retArray = array();
array_push($retArray, $array[1], $array[2], $array[3]);
return $retArray;
}
This will do the trick. Not the most elegant example due to the free function with a static variable, but you can make it more elegant by using a lambda or an instance of a class for the callback target.
function filter($subArray) {
static $seenKeys = null;
if ($seenKeys === null) {
$seekKeys = array();
}
// I 'm just selecting the "three first" indexes here,
// you can change it to better suit your needs
$thisKey = serialize(array_slice($subArray, 0, 3));
if (isset($seenKeys[$thisKey])) {
return false;
}
else {
return $seenKeys[$thisKey] = true;
}
}
$result = array_filter($inputArray, 'filter');
I think this example is as fast as you can go in PHP without making assumptions about the type and/or values of the first three items in each subarray. If any such assumption can be made, then at the very least the serialize call can be replaced with something more appropriate. I imagine that this would speed up the process quite a bit.

Categories