Splitting a Associative Array Based off if Condition of Value - php

I'm combining an array based off a MySQL Query:
$newskus = array();
$newqtys = array();
$sql1 = $db->query("//QUERY//");
while($row = $sql1->fetch_assoc()) {
$newskus[] = $row['SKU'];
$newqtys[] = $row['Quantity'];
}
$newskusandqtys = array_combine($newskus, $newqtys);
This gives me an associative array like so:
Array
(
[Product 1] => -1
[Product 2] => 0
[Product 3] => 3
)
I'm looking to split this array based off the condition of the integer value.
That is, if the value is above 0, it'll put the contents into a variable $newqtysabovezero
Ending with an expected output of
Array
(
[Product 3] => 3
)
And the other way around, if the value is greater than or equal to 0, put this into an array variable $newqtysbelowzero with an expected output of
Array
(
[Product 1] => -1
[Product 2] => 0
)
I'm able to do this with a numerical array, but it of course is not passing the key:
foreach( $newqtys as $item ) {
if ( $item > '0' ) {
$newqtysabovezero[] = $item;
} elseif ( $item <= '0') {
$newqtysbelowzero[] = $item;
}
}
How would I modify this to get my expected output?

Here is one way:
foreach( $newqtys as $key => $item ) {
if ( $item > '0' ) {
$newqtysabovezero[$key] = $item;
} elseif ( $item <= '0') {
$newqtysbelowzero[$key] = $item;
}
}
And here is a method using array_filter():
$in = array(
'Product 1' => -1,
'Product 2' => 0,
'Product 3' => 3
);
function at_and_below($v) {
return $v <= 0;
}
function above($v) {
return $v > 0;
}
$newqtysabovezero = array_filter($in, 'above');
$newqtysbelowzero = array_filter($in, 'at_and_below');

At first, to get all values from the 'Quantity' field as integers you should cast them to integer type:
...
while($row = $sql1->fetch_assoc()) {
$newskus[] = $row['SKU'];
$newqtys[] = (int) $row['Quantity'];
}
$newskusandqtys = array_combine($newskus, $newqtys);
Then, you can easily separate values which are greater than OR equal/less than 0:
foreach (newskusandqtys as $k => $item) {
if ($item > 0) {
$newqtysabovezero[$k] = $item;
} else {
$newqtysbelowzero[$k] = $item;
}
}

You can skip the array_combine part, and just read the values into the final arrays as you fetch them.
while($row = $sql1->fetch_assoc()) {
if ($row['Quantity'] > 0) {
$newqtysabovezero[$row['SKU']] = $row['Quantity'];
} else {
$newqtysbelowzero[$row['SKU']] = $row['Quantity'];
}
}

Related

Search a multidimensional array for duplicates and return duplicate values and array key

I have the following multidimensional array:
$ancestors = array(
[1] =>array("Andrew","Adele"),
[2] =>array("Bertha","Bill","Billy","Blake"),
[3] =>array("Cathy","Case","Cory","Creek","Andrew","Ceaser","Cece","Childer"));
I am trying to search the rows and return duplicate values along with the array key of the lowest number the duplicate appears and return values to an associative array:
$common = array("Andrew"=>"1");
// merge all array in one
$new = array();
foreach($ancestors as $i)
$new = array_merge($new, $i);
// make array value => count and sort in in descendant order
$ar = array_count_values($new);
arsort($ar);
// save result array while count > 1
$result = array();
foreach($ar as $k => $v) {
if ($v < 2) break;
$result[$k] = array_search($k, $new) + 1;
}
print_r($result);
We have to compare each row with following rows, so row 1 with 2 and 3, row 2 with 3, row 3 with nothing (it is already compared).
To do this, we use a base-1 for to loop through all $ancestors elements except last, then we compare each name with greater ancestors:
$result = array();
/* Loop count($ancestors) -1: */
for( $i = 1; $i<count( $ancestors ); $i++ )
{
/* Loop for each name: */
foreach( current( $ancestors ) as $val )
{
/* If name is already in result, skip: */
if( isset( $result[$val] ) ) continue;
/* Loop for each following ancestors: */
foreach( array_slice( $ancestors, $i, Null, True ) as $key => $row )
{
if( in_array( $val, $row ) ) $result[ $val ] = key( $ancestors );
}
}
next( $ancestors );
}
For this $ancestors:
$ancestors = array(
1 =>array( "Andrew","Adele" ),
2 =>array( "Bertha","Bill","Billy","Blake","Adele" ),
3 =>array( "Cathy","Case","Cory","Creek","Andrew","Ceaser","Bill","Cece","Childer" ),
4 =>array( "Cathy" )
);
the result is:
Array
(
[Andrew] => 1
[Adele] => 1
[Bill] => 2
[Cathy] => 3
)
First combine all the names into one array, with names as keys and arrays of generation indexes as values:
foreach ($ancestors as $generation_key => $generation) {
foreach ($generation as $name) {
$combined[$name][] = $generation_key;
}
}
Then limit the combined results to values having more than one instance of the name:
$duplicates = array_filter($combined, function($x) { return count($x) > 1; });
Then convert the arrays to single values using min:
foreach ($duplicates as &$value) {
$value = min($value);
}
unset($value);

in a key value array, how to increment array value in foreach loop

I have an array
$rel = array('grandfather' => 0 ,
'grandmother' => 0 ,
'father' => 0 ,
'sister' => 0 ,
);
I want it to compare to the array $family from
$data['family'] = $facebook->api('/me/family?fields=name,relationship,education,location,cover');
using the foreach loop
foreach ($family as $families) {
foreach ($families as $fams) {
$id = $fams['id'];
$name = $fams['name'];
$relationship = $fams['relationship'];
foreach($rel as $k => $val){
if($k == $relationship)
{
$val += 1;
}
}
}
}
i want the $val to increment in each iteration such that if I have 5 sisters.. when i will
print_r($rel);
the result would be
Array ( [grandfather] => 0 [grandmother] => 0 [father] => 0 [sister] => 5 )
i have tried the above code but it still returns to 0..
try this
if($k == $relationship)
{
$rel[$k] += 1;
}
It should work.
foreach ($family as $families) {
foreach ($families as $fams) {
$id = $fams['id'];
$name = $fams['name'];
$relationship = $fams['relationship'];
foreach($rel as $k => $val){
if($k == $relationship)
{
$rel[$relationship]++;
}
}
}
}

PHP update quantity in multidimensional array

My array looks like the following:
Array
(
[0] => Array
(
[index] => 0
[quantity] => 1
[0] => Array
(
[id_product] => 20
[title] => Oranges
)
)
[1] => Array
(
[index] => 1
[quantity] => 1
[0] => Array
(
[id_product] => 24
[title] => Bananas
)
)
)
To make this array, this is my code:
$i = 0;
$content = array();
if(isset($_SESSION['cart'])){
foreach($_SESSION['cart'] as $result){
foreach($result as $item){
$values = $product->getById($item['id']);
if($values != null){ // which means it has product
/*
Checks if the array already contains that ID
this avoids duplicated products
*/
if(main::search_multidimensional($content, "id_product", $item['id_product']) == null){
$content[] = array("index" => $i, "quantity" => 1, $values);
$i++;
}else{ /*
in case it does have already the id_product in the array
I should update the "quantity" according to the "index".
*/
}
}
}
}
}
return $content;
My problem is after the }else{. I've been trying some codes without any success. I have to update the quantity according to the index. Although if you guys think there's a better alternative please let me know.
Edit: Since most of the people is worried about the search_multidimensional and it might be my solution, here's the function:
public function search_multidimensional($array, $key, $value){
$results = array();
if (is_array($array)) {
if (isset($array[$key]) && $array[$key] == $value) {
$results[] = $array;
}
foreach ($array as $subarray) {
$results = array_merge($results, self::search_multidimensional($subarray, $key, $value));
}
}
return $results;
}
EDIT 2:
In that case, would this help? (Since your search_multidimensional only returns a true or false)
$i = 0;
$content = array();
if(isset($_SESSION['cart'])){
foreach($_SESSION['cart'] as $result){
foreach($result as $item){
$values = $product->getById($item['id']);
if($values != null) { // which means it has product
/*
Checks if the array already contains that ID
this avoids duplicated products
*/
$product_exists = false;
foreach($content as &$cItem) {
if($cItem['values']['id_product'] == $item['id_product']) {
$cItem['values']['quantity']++; // Increments the quantity by 1
$product_exists = true;
break;
}
}
// If the product does not exist in $content, add it in.
if(!$product_exists)
$content[] = array("index" => $i, "quantity" => 1, "values" => $values);
$i++;
}
}
}
}
(Edited again to give an array key to $values)
OLD ANSWER:
Since you are recreating the cart array in $content, you could just do this in your else:
$content[] = array("index" => $i, "quantity" => $result['quantity'] + 1, $values);
Such that it would show like this:
$i = 0;
$content = array();
if(isset($_SESSION['cart'])){
foreach($_SESSION['cart'] as $result){
foreach($result as $item){
$values = $product->getById($item['id']);
if($values != null){ // which means it has product
/*
Checks if the array already contains that ID
this avoids duplicated products
*/
if(main::search_multidimensional($content, "id_product", $item['id_product']) == null)
$content[] = array("index" => $i, "quantity" => 1, $values);
else
$content[] = array("index" => $i, "quantity" => $result['quantity'] + 1, $values); // Retrieve current quantity and adds 1
$i++;
}
}
}
}
(I'm assuming you are only increasing the quantity by 1)
Solved.
All I had to do was to forget the $i variable, since it wasn't actually doing something necessary. Since I have id_product, which is unique I need to work with it.
if($values != null){ // Only if it has results
// checks if array already contains or not the product ID
// if does not have, it will add
if(global_::search_multidimensional($content, "id_product", $item['id_product']) == null){
$content[] = array("index" => $item['id_product'], "quantity" => 1, $values);
// index is now the id of the product
}else{
// otherwise, loop all the elements and add +1
foreach($content as $key => $result){
if($item['id_product'] == $content[$key]['index']){
$content[$key]['quantity']++;
}
}
}
}
As your $content array has fixed structure (fixed number of levels) you don't need to use recursive function. Your search_multidimensional function could be much simpler. And it should return index of found element (if any) in the array:
function search_multidimensional($array, $key, $value) {
foreach ($array as $i => $el) {
foreach ($el as $j => $v) {
if (is_int($j) && isset($v[$key]) && $v[$key] == $value) return $i;
}
}
return false;
}
So the snippet building $content should be changed like this:
...
if (($index = search_multidimensional($content, "id_product", $item['id_product'])) === false) {
$content[] = array("index" => $i, "quantity" => 1, $values); $i++;
}
else {
$content[$index]['quantity']++;
}

PHP: Count the appearance of particular value in array

I am wondering if I could explain this.
I have a multidimensional array , I would like to get the count of particular value appearing in that array
Below I am showing the snippet of array . I am just checking with the profile_type .
So I am trying to display the count of profile_type in the array
EDIT
Sorry I've forgot mention something, not something its the main thing , I need the count of profile_type==p
Array
(
[0] => Array
(
[Driver] => Array
(
[id] => 4
[profile_type] => p
[birthyear] => 1978
[is_elite] => 0
)
)
[1] => Array
(
[Driver] => Array
(
[id] => 4
[profile_type] => d
[birthyear] => 1972
[is_elite] => 1
)
)
)
Easy solution with RecursiveArrayIterator, so you don't have to care about the dimensions:
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
$counter = 0
foreach ($iterator as $key => $value) {
if ($key == 'profile_type' && $value == 'p') {
$counter++;
}
}
echo $counter;
Something like this might work...
$counts = array();
foreach ($array as $key=>$val) {
foreach ($innerArray as $driver=>$arr) {
$counts[] = $arr['profile_type'];
}
}
$solution = array_count_values($counts);
I'd do something like:
$profile = array();
foreach($array as $elem) {
if (isset($elem['Driver']['profile_type'])) {
$profile[$elem['Driver']['profile_type']]++;
} else {
$profile[$elem['Driver']['profile_type']] = 1;
}
}
print_r($profile);
You may also use array_walk($array,"test") and define a function "test" that checks each item of the array for 'type' and calls recursively array_walk($arrayElement,"test") for items of type 'array' , else checks for the condition. If condition satisfies, increment a count.
Hi You can get count of profuke_type==p from a multi dimensiona array
$arr = array();
$arr[0]['Driver']['id'] = 4;
$arr[0]['Driver']['profile_type'] = 'p';
$arr[0]['Driver']['birthyear'] = 1978;
$arr[0]['Driver']['is_elite'] = 0;
$arr[1]['Driver']['id'] = 4;
$arr[1]['Driver']['profile_type'] = 'd';
$arr[1]['Driver']['birthyear'] = 1972;
$arr[1]['Driver']['is_elite'] = 1;
$arr[2]['profile_type'] = 'p';
$result = 0;
get_count($arr, 'profile_type', 'd' , $result);
echo $result;
function get_count($array, $key, $value , &$result){
if(!is_array($array)){
return;
}
if($array[$key] == $value){
$result++;
}
foreach($array AS $arr){
get_count($arr, $key, $value , $result);
}
}
try this..
thanks

most efficient method of turning multiple 1D arrays into columns of a 2D array

As I was writing a for loop earlier today, I thought that there must be a neater way of doing this... so I figured I'd ask. I looked briefly for a duplicate question but didn't see anything obvious.
The Problem:
Given N arrays of length M, turn them into a M-row by N-column 2D array
Example:
$id = [1,5,2,8,6]
$name = [a,b,c,d,e]
$result = [[1,a],
[5,b],
[2,c],
[8,d],
[6,e]]
My Solution:
Pretty straight forward and probably not optimal, but it does work:
<?php
// $row is returned from a DB query
// $row['<var>'] is a comma separated string of values
$categories = array();
$ids = explode(",", $row['ids']);
$names = explode(",", $row['names']);
$titles = explode(",", $row['titles']);
for($i = 0; $i < count($ids); $i++) {
$categories[] = array("id" => $ids[$i],
"name" => $names[$i],
"title" => $titles[$i]);
}
?>
note: I didn't put the name => value bit in the spec, but it'd be awesome if there was some way to keep that as well.
Maybe this? Not sure if it's more efficient but it's definitely cleaner.
/*
Using the below data:
$row['ids'] = '1,2,3';
$row['names'] = 'a,b,c';
$row['titles'] = 'title1,title2,title3';
*/
$categories = array_map(NULL,
explode(',', $row['ids']),
explode(',', $row['names']),
explode(',', $row['titles'])
);
// If you must retain keys then use instead:
$withKeys = array();
foreach ($row as $k => $v) {
$v = explode(',', $v);
foreach ($v as $k2 => $v2) {
$withKeys[$k2][$k] = $v[$k2];
}
}
print_r($categories);
print_r($withKeys);
/*
$categories:
array
0 =>
array
0 => int 1
1 => string 'a' (length=1)
2 => string 'title1' (length=6)
...
$withKeys:
array
0 =>
array
'ids' => int 1
'names' => string 'a' (length=1)
'titles' => string 'title1' (length=6)
...
*/
Just did a quick simple benchmark for the 4 results on this page and got the following:
// Using the following data set:
$row = array(
'ids' => '1,2,3,4,5',
'names' => 'abc,def,ghi,jkl,mno',
'titles' => 'pqrs,tuvw,xyzA,BCDE,FGHI'
);
/*
For 10,000 iterations,
Merge, for:
0.52803611755371
Merge, func:
0.94854116439819
Merge, array_map:
0.30260396003723
Merge, foreach:
0.40261697769165
*/
Yup, array_combine()
$result = array_combine( $id, $name );
EDIT
Here's how I'd handle your data transformation
function convertRow( $row )
{
$length = null;
$keys = array();
foreach ( $row as $key => $value )
{
$row[$key] = explode( ',', $value );
if ( !is_null( $length ) && $length != count( $row[$key] ) )
{
throw new Exception( 'Lengths don not match' );
}
$length = count( $row[$key] );
// Cheap way to produce a singular - might break on some words
$keys[$key] = preg_replace( "/s$/", '', $key );
}
$output = array();
for ( $i = 0; $i < $length; $i++ )
{
foreach ( $keys as $key => $singular )
{
$output[$i][$singular] = $row[$key][$i];
}
}
return $output;
}
And a test
$row = convertRow( $row );
echo '<pre>';
print_r( $row );

Categories