Sorting 'key=>value' pair multi-dimensional arrays in PHP - php

I am creating a site and I am trying to do a few complicated things with arrays to get it to work.
It is for an e-commerce site and each product on my site can have a number of attributes. I am trying to get each combination of attributes to do the pricing for them seperately.
First I get an array of the attribute ids ($attribute_id_array) and the query the database for the options for that array.
So if one attribute was colors the options here would be red,green,blue,etc,. or size would be small,medium,large,etc,. These are then stored in a new array ($attribute_arrays).
I then go through these to get every combination of attributes the product can have and sort these into a new array again ($new_attributes_array).
I then loop through this and create a price form for each combination.
$attribute_arrays = [];
foreach($attribute_id_array as $attribute_id){
$params = [$attribute_id];
$sql = "SELECT * FROM attributes WHERE id=?";
$attributeResult = DB::run($sql,$params);
while($row = $attributeResult->fetch(PDO::FETCH_ASSOC)){
array_push($attribute_arrays,$row);
}
}
var_dump($attribute_arrays);
function combinations($arrays, $i = 0) {
if (!isset($arrays[$i])) {
return array();
}
if ($i == count($arrays) - 1) {
return $arrays[$i];
}
$tmp = combinations($arrays, $i + 1);
$result = array();
foreach ($arrays[$i] as $v) {
foreach ($tmp as $t) {
$result[] = is_array($t) ?
array_merge(array($v), $t) :
array($v, $t);
}
}
return $result;
}
$new_attributes_array = combinations($attribute_arrays);
var_dump($new_attributes_array);
This is all working fine except I want to be able to get the keys for all of the key value pairs so I can reference it back to my database.
The way it comes out at the moment is like this:
$attribute_id_array:
array (size=2)
1 => string '5' (length=1)
2 => string '7' (length=1)
$attribute_arrays:
0 =>
array (size=2)
'attribute1' => string 'Step Through Bars' (length=17)
'attribute2' => string 'Gated' (length=5)
1 =>
array (size=2)
'attribute1' => string '3 metres' (length=8)
'attribute2' => string '6 metres' (length=8)
$new_attributes_array:
0 =>
array (size=2)
0 => string 'Step Through Bars' (length=17)
1 => string '3 metres' (length=8)
1 =>
array (size=2)
0 => string 'Step Through Bars' (length=17)
1 => string '6 metres' (length=8)
2 =>
array (size=2)
0 => string 'Gated' (length=5)
1 => string '3 metres' (length=8)
3 =>
array (size=2)
0 => string 'Gated' (length=5)
1 => string '6 metres' (length=8)
Is there a way to get it so that the key will be similar in format to:
0 =>
array (size=2)
5-attribute1 => string 'Step Through Bars' (length=17)
7-attribute1 => string '3 metres' (length=8)
1 =>
array (size=2)
5-attribute1 => string 'Step Through Bars' (length=17)
7-attribute2 => string '6 metres' (length=8)
Edit
So I changed the line array_push($attribute_arrays,$row); to $attribute_arrays[$attribute_id] = $row;.
This now means that $attribute_arrays now has the$attribute_id variable as the key like so:
array (size=2)
5 =>
array (size=2)
'attribute1' => string 'Step Through Bars' (length=17)
'attribute2' => string 'Gated' (length=5)
7 =>
array (size=2)
'attribute1' => string '3 metres' (length=8)
'attribute2' => string '6 metres' (length=8)
This now means my other function for getting the combinations won't work as it is using the $i variable as the index for the array starting at '0'.
Found another function online to sort it here How to generate in PHP all combinations of items in multiple arrays:
function combinations($arrays) {
$result = array(array());
foreach ($arrays as $property => $property_values) {
$tmp = array();
foreach ($result as $result_item) {
foreach ($property_values as $property_key => $property_value) {
$tmp[] = $result_item + array($property_key => $property_value);
}
}
$result = $tmp;
}
return $result;
}
However, this doesn't do exactly as I want and I end up with this:
array (size=4)
0 =>
array (size=1)
'attribute1' => string 'Step Through Bars' (length=17)
1 =>
array (size=2)
'attribute1' => string 'Step Through Bars' (length=17)
'attribute2' => string '6 metres' (length=8)
2 =>
array (size=2)
'attribute2' => string 'Gated' (length=5)
'attribute1' => string '3 metres' (length=8)
3 =>
array (size=1)
'attribute2' => string 'Gated' (length=5)

try this as your combinations function
modified code taken from here
function combinations($arrays) {
$result = array(array());
foreach ($arrays as $key => $values) {
$tmp = array();
foreach ($result as $item) {
foreach ($values as $k=>$value) {
$tmp[] = array_merge($item, array($key.'-'.$k => $value));
}
}
$result = $tmp;
}
return $result;
}

Instead of using while on following line
while($row = $attributeResult->fetch(PDO::FETCH_ASSOC)){
Use foreach loop to get key paired value. e.g
foreach($databaseFetchedRecord as $mykey=>$myvalue)

Related

php array count values in 4 deep array

Im trying to count how many times a delivery date is in my array but i seem to only be able to count the first level.
array (size=48)
'2000-01-01' =>
array (size=2)
'date' => string '2000-01-01' (length=10)
0 =>
array (size=2)
'van' => string '0' (length=1)
0 =>
array (size=619)
'drop' => string '0' (length=1)
0 =>
array (size=29)
'id' => string '18137' (length=5)
'order_number' => string '13550' (length=5)
'reference' => string '' (length=0)
'delivery_date' => string '2000-01-01' (length=10)
I've tried:
$counts = array_count_values(array_flip(array_column($output, 'delivery_date')));
and
$array = array_map(function($element){
return $element['delivery_date'];
}, $output);
$array2 = (array_count_values($array));
print_r($array2);
in the end i either end up with a array to string error or the value 1.
how Would i go about counting these?
Thanks.
You could make use of array_walk_recursive and increment an array value every time the delivery_date key is present in the array at any level:
$counts = [];
array_walk_recursive(
$output,
static function ($value, string $key) use (&$counts): void {
if ($key === 'delivery_date') {
$counts[$value] = ($counts[$value] ?? 0) + 1;
}
}
);

Store unique values within foreach loop

Im trying to get value of ids for different values of a foreach loop but im confused how to go about it.
$revenue = array('pseudo1', 'pseudo2');
foreach ($revenue as $value) {
if (!$revenue_type) {
$st = getValueDescription($value);
foreach ($st as $stype) {
$tpe[] = $stype->id;
}
$rev[$value] = $tpe;
}
}
when i dump $rev this is what i get
array (size=1)
0 =>
array (size=3)
'pseudo1' =>
array (size=2)
0 => string '9' (length=1)
1 => string '19' (length=2)
'pseudo2' =>
array (size=4)
0 => string '9' (length=1)
1 => string '19' (length=2)
2 => string '1' (length=1)
3 => string '35' (length=2)
what i actually expect
array (size=1)
0 =>
array (size=3)
'pseudo1' =>
array (size=2)
0 => string '9' (length=1)
1 => string '19' (length=2)
'pseudo2' =>
array (size=4)
2 => string '1' (length=1)
3 => string '35' (length=2)
I need the result of my $rev to contain $value as keys but previous values of $tpe keeps adding up with each iteration, im confused how to achieve this.
Does this solve your problem?
$revenue = array('pseudo1', 'pseudo2');
$uniqueValues = [];
foreach ($revenue as $value) {
if (!$revenue_type) {
$st = getValueDescription($value);
$tpe = [];
foreach ($st as $stype) {
if (!in_array($stype->id, $uniqueValues)) {
$tpe[] = $stype->id;
$uniqueValues[] = $stype->id;
}
}
$rev[$value] = $tpe;
}
}
$uniqueValues holds the IDS you already added to the $rev variable, and the $tpe gets empty after every iteration

String to Nested Array

Hi i would like to ask if there is any good way to make Nested Array from few strings like in example but when i add NEW STRING it should append
it looks like some kind of tree
String
TEXT1|||TEXT2|||TEXT3 ....
into
[TEXT1 => [TEXT2 => [TEXT3] ] ]
new String
TEXT1|||AAA222|||AAA333
mew array with old one
[TEXT1 => [TEXT2 => [TEXT3 => null], AAA222 => [AAA333 => null] ] ]
string is generated from this array indexes are levels in "tree"
array (size=5)
0 =>
array (size=2)
'a' => string 'Motoryzacja' (length=11)
'b' => string '' (length=0)
1 =>
array (size=2)
'a' => string 'Części samochodowe' (length=20)
'b' => string '' (length=0)
2 =>
array (size=2)
'a' => string 'Części karoserii' (length=18)
'b' => string '' (length=0)
3 =>
array (size=2)
'a' => string 'Błotniki' (length=9)
'b' => string '' (length=0)
4 =>
array (size=2)
'a' => string 'Maski' (length=5)
'b' => string '' (length=0)
This is what I came up with:
//recursive function to build the array
function buildArray(Array $input, $output=[]){
$len = count($input);
if ($len > 0){
$key = array_shift($input);
//if there is more in the array, then we need to continue building our array
if (($len - 1) > 0){
$output[$key] = buildArray($input,$output);
}
else {
$output[$key] = NULL;
}
}
return $output;
}
//converts string input with ||| delimiter into nested Array
function stringToArray(String $input){
$arr = explode('|||', $input);
$output = buildArray($arr);
return $output;
}
$arr = stringToArray("TEXT1|||TEXT2|||TEXT3");
$arr2 = stringToArray("TEXT1|||AAA222|||AAA333");
var_dump(array_merge_recursive($arr,$arr2));

Add entries together based on key in array PHP

As you can see I have a key called dateTime which holds dates. What I need to do is add all the entries together for each date and return the array. So I simply got one dateTime per date with all the entries of that day added together. I do not know the dateTime inputs ahead of time as I have a crawler that constantly inserts data into my database.
How would you go about doing that in the most efficient way? I imagine I would have to do a foreach loop and somehow check if the key value (dateTime) changes from the previous key value. And then create a brand new array that I return
An example of the array is as follows:
array (size=130)
0 =>
array (size=2)
'dateTime' => string '2015-09-01' (length=10)
'entries' => string '225' (length=3)
1 =>
array (size=2)
'dateTime' => string '2015-09-01' (length=10)
'entries' => string '218' (length=3)
2 =>
array (size=2)
'dateTime' => string '2015-09-01' (length=10)
'entries' => string '217' (length=3)
3 =>
array (size=2)
'dateTime' => string '2015-09-01' (length=10)
'entries' => string '225' (length=3)
4 =>
array (size=2)
'dateTime' => string '2015-09-02' (length=10)
'entries' => string '231' (length=3)
5 =>
array (size=2)
'dateTime' => string '2015-09-02' (length=10)
'entries' => string '220' (length=3)
6 =>
array (size=2)
'dateTime' => string '2015-09-03' (length=10)
'entries' => string '223' (length=3)
7 =>
array (size=2)
'dateTime' => string '2015-09-03' (length=10)
'entries' => string '237' (length=3)
8 =>
array (size=2)
'dateTime' => string '2015-09-03' (length=10)
'entries' => string '220' (length=3)
So it returns an array like this
array (size=130)
0 =>
array (size=2)
'dateTime' => string '2015-09-01' (length=10)
'entries' => string '660' (length=3)
1 =>
array (size=2)
'dateTime' => string '2015-09-02' (length=10)
'entries' => string '451' (length=3)
2 =>
array (size=2)
'dateTime' => string '2015-09-03' (length=10)
'entries' => string '680' (length=3)
Edit With the help of you guys, I ended up doing the following to get the right format.
function prepareArrayForGraphDates($array){
$results = [];
$finalResult = [];
foreach ($array as $value) {
if (!isset($results[$value['dateTime']])) {
$results[$value['dateTime']] = 0;
}
$results[$value['dateTime']] += $value['entries'];
}
$keyNames = array_keys($results);
for ($x = 0; $x < sizeof($results); $x++) {
$finalResult[$x]['dateTime'] = $keyNames[$x];
$finalResult[$x]['entries'] = $results[$keyNames[$x]];
}
return $finalResult;
}
Use the fact that array keys are unique...
$results = [];
foreach ($array as $value) {
if (!isset($results[$value['dateTime']])) {
$results[$value['dateTime']] = 0;
}
$results[$value['dateTime']] += $value['entries'];
}
You can use an array like a set or a dictionary, using the date as the key.
$data = [
[
'datetime'=>'2015-09-02',
'entries' => 220
]
// ... other entries snipped ...
];
$results = [];
foreach ($data as $date => $entry)
{
// if the date has already been recorded with an initial value, add to it
if (array_key_exists($date, $results) {
$results[$date] += $entry
} else {
// the date is new; add it to the results and set its initial value
$results[$date] = $entry;
}
}

Find arrays that share a common value from collection of arrays. May be 0 or more matches

I have the following data structure:
array (size=3)
0 =>
array (size=4)
0 => string 'apple' (length=5)
1 => string 'colophon' (length=8)
2 => string 'byo-fusion-drive' (length=16)
3 => string 'scroll-targeting' (length=16)
1 =>
array (size=3)
0 => string 'apply' (length=5)
1 => string 'exploring-web-typography' (length=24)
2 => string 'on-performance-content-management' (length=33)
2 =>
array (size=3)
0 => string 'macbook' (length=7)
1 => string 'colophon' (length=8)
2 => string 'nifty-minidrive' (length=15)
I'm trying to find out which, if any, arrays in my collection of arrays share a common value.
E.g: Arrays 0 and 2 share the string "colophon".
I've tried using array_intersect but this, of course, returns NULL since array 1 has no values in common with the others.
Also, it's possible (likely even) that in any given collection there will be no common value. The collection of arrays will always contain at least two arrays. There could be any number of additional arrays in the collection.
With the data described above, the end result should be something like this:
array (size=2)
0 =>
array (size=4)
0 => string 'apple' (length=5)
1 => string 'colophon' (length=8)
2 => string 'byo-fusion-drive' (length=16)
3 => string 'scroll-targeting' (length=16)
1 =>
array (size=3)
0 => string 'macbook' (length=7)
1 => string 'colophon' (length=8)
2 => string 'nifty-minidrive' (length=15)
I.e: With array 1 (from the original) being removed as it shares no common value.
I'm sure there's a simple way to do this, but I have been trying for 8+ hours now and have decided to ask for help.
Anyone?
You'll need to iterate it with a nested loop. like so:
$array = array(
array(
"apple",
"colophon",
"byo-fusion-drive",
"scroll-targeting"
),
array(
"apply",
"exploring-web-typography",
"on-performance-content-management"
),
array(
"macbook",
"colophon",
"nifty-minidrive"
)
);
for ($i = 0; $i < count($array); $i++) {
for ($j = $i+1; $j < count($array); $j++) {
var_dump(array_intersect($array[$i], $array[$j]));
}
}
Which outputs:
array (size=0)
empty
array (size=1)
1 => string 'colophon' (length=8)
array (size=0)
empty
A simple modification to the loop gives the expected behavior:
$result = array();
for ($i = 0; $i < count($array); $i++) { //Start from the first array, and continue up to all of them.
for ($j = $i+1; $j < count($array); $j++) { //Start with the current array of $i, +1. So that collisions never occur.
if (count(array_intersect($array[$i], $array[$j])) !== 0) { //If there are common values (the array_intersect() function returns a non-empty array
if (!in_array($array[$i], $result)) $result[] = $array[$i]; //Add the first array (if it's not there already)
if (!in_array($array[$j], $result)) $result[] = $array[$j]; //Add the second array (if it's not there already)
}
}
}
Which outputs
array (size=2)
0 =>
array (size=4)
0 => string 'apple' (length=5)
1 => string 'colophon' (length=8)
2 => string 'byo-fusion-drive' (length=16)
3 => string 'scroll-targeting' (length=16)
1 =>
array (size=3)
0 => string 'macbook' (length=7)
1 => string 'colophon' (length=8)
2 => string 'nifty-minidrive' (length=15)
Try
$arr = array (
array('apple', 'colophon', 'byo-fusion-drive', 'scroll-targeting', ),
array('apply', 'exploring-web-typography', 'on-performance-content-management', ),
array('macbook', 'colophon', 'nifty-minidrive', 'nifty-minidrive', ),
);
$repeated_values = array_keys(
array_filter(
array_count_values(
array_reduce($arr, function ($res, $value) {
return array_merge($res, array_unique($value));
}, array()
)
), function ($count) {
return $count > 1;
})
);
$result = array_filter($arr, function($value) use ($repeated_values) {
if (sizeof(array_intersect($repeated_values, $value)) > 0) return true;
});
var_dump($result);
Output
array (size=2)
0 =>
array (size=4)
0 => string 'apple' (length=5)
1 => string 'colophon' (length=8)
2 => string 'byo-fusion-drive' (length=16)
3 => string 'scroll-targeting' (length=16)
2 =>
array (size=4)
0 => string 'macbook' (length=7)
1 => string 'colophon' (length=8)
2 => string 'nifty-minidrive' (length=15)
3 => string 'nifty-minidrive' (length=15)

Categories