Associative array: Dynamically adding values creates duplicate keys - php

I declare an array like this:
$statement_row = array(
"Key 1" => "",
"Key 2" => "",
"Key 3" => "");
Then I read data from one table that have corresponding keys in column 0 and value in column 3 so I loop over each row in that table like this:
foreach($table_row as $value){
if(!empty($value[0])){
$statement_row[ $value[0] ] = $value[3];
}
}
This gives an array with duplicate keys of key 1, key 2 and key 3, like this:
array("Key 1" => "","Key 2" => "","Key 3" => "","Key 1" => "Holds value","Key 2" => "Holds value","Key 3" => "Holds value");
Why does it behave like this? Is $value[0] not threated the same way as the defined keys?

Related

Extract data using index, not name

I am parsing a csv file, and then looping it like so.
foreach ($this->csvData as $dataKey => &$item) {
foreach ($item as $key => $value) {
print_r($item);
}
}
Now if I output item, I can see something like the following
array:12 [
"ID" => "12345"
"CODE" => "AZ6G"
"YEAR" => "2009"
"WEEK" => "13"
"FULL_DATE" => "29/04/2014"
"SALES" => "asdas89.34"
"QUANTITY" => "3"
]
So the above example represents one row in the csv, the key is the header name and then it has a value.
The problem is this, I know which columns I need to keep based on an index value. These values are selected by the user at a previous stage. So in the above example I know I need to keep the ID, FULL_DATE and SALES, so in my database I have 0, 4, 5 which represents their indexes.
Now I need to extract these columns. If I do something like the following
foreach ($this->csvData as $dataKey => &$item) {
foreach ($item as $key => $value) {
print_r($item[4]);
}
}
I will get an undefined index problem as there is no key named 4. If I give it the name of the key, it will work, and show me the value.
So how can I get the value using the key index instead of the name?
Thanks
you could use array_keys and then loop over those keys you said you get from the Database like so:
<?php
$keys = [0, 4, 5];
$data = [
"ID" => "12345",
"CODE" => "AZ6G",
"YEAR" => "2009",
"WEEK" => "13",
"FULL_DATE" => "29/04/2014",
"SALES" => "asdas89.34",
"QUANTITY" => "3"
];
foreach($keys as $key) {
echo $data[array_keys($data)[$key]] . "\n";
}
// outputs:
// 12345
// 29/04/2014
// asdas89.34
Explanation what happens:
array_keys($data)[0]; // is "ID"
// and the "ID" can be used as "key" for the $data array with
$data[array_keys($data)[0]]; // which is $data["ID"]; => "12345"
You can play with it online here: http://sandbox.onlinephpfunctions.com/code/4d6a4d86a6cdceccf4034fca06dcef9e50a89dc8

Skip key index from a range of array's key in php

This is only for arrays with index number. For example i have this arrays;
$array = [
"0" => "number 1",
"1" => "number 2",
"2" => "number 3",
"3" => "number 4",
"4" => "number 5",
"5" => "number 6",
"6" => "number 7",
"7" => "number 8",
"8" => "number 9"
];
I want to skip the loop from certain range of key indexes for example, skip the foreach if the number of index is from range 0 to 5. That means we can do just like this.
foreach($array as $key => $value){
if(array_key_exist($key, range(0,5))
continue;
echo $value."<br/>"
}
or we can using for... loop
for($ind = 0; $ind < count($array); $ind++){
if(array_key_exist($ind, range(0,5))
continue;
echo $arr[$ind]."<br/>"
}
How could i skip the index without using continue or searching the array_key first ? sure the code above looks fine to me, but if i have a bunch of arrays keys and values, i think this is not a good choice.
You can use array_diff as:
$wantKeys = array_diff(array_keys($array), range(1,5));
Now all you need is loop on the $wantKeys as:
foreach($wantKeys as $k)
echo $array[$k]; // only wanted values
The same idea can be achieve by array_diff_keys:
$wantKeys = array_diff_key($array, array_flip(range(1,5)));
You can get the slice of array from 5th index to rest,
$result = array_slice($array,5,count($array)-5, true);
array_slice — Extract a slice of the array
Note:
array_slice() will reorder and reset the integer array indices by
default. This behaviour can be changed by setting preserve_keys to
TRUE. String keys are always preserved, regardless of this parameter.
Demo.

Merging 2 arrays based on a relational array

I have the following arrays:
$excel_arr = array(
["C1", "Title 3"],
["A1", "Title 1"],
["B1", "Title 2"],
["D1", "Title 4"]
);
$db_result = array(
"title_2" => "Cell 2 Value",
"title_1" => "Cell 1 Value",
"title_3" => "Cell 3 Value",
"title_5" => "Cell 5 Value"
);
$excel_db_relation = array(
"title_1" => "Title 1",
"title_2" => "Title 2",
"title_3" => "Title 3",
"title_4" => "Title 4",
"title_5" => "Title 5"
);
usort($excel_arr, function ($a, $b) { return strnatcmp($a[0], $b[0]); });
$excel_arr is an array with the titles for each column in an excel file. The first cell defines the cell coordinate and the second the actual cell value.
$db_result is an array containing queried values from a database. The key is column name in the table.
$excel_db_relation is an array which defines the relation between the 2 former arrays. Which excel column is linked to which db table column. In this example they are very similar, but in practice there might be more than just an underscore that differs.
The cell coordinates in $excel_arr defines the order in which each value must be printed. To do this I sort the array with the usort() as seen above.
I need to somehow merge these arrays so that the resulting array becomes:
array("Title 1" => "Cell 1 Value", "Title 2" => "Cell 2 Value", "Title 3" => "Cell 3 Value")
The database array didn't return a value for cell 4 and the excel sheet doesn't define a E5 cell. So these must not be included in the resulting array.
I have tried array_merge($excel_db_relation, $db_result) and various combinations of array_merge() and array_flip() but no matter what I do I can't seem to merge the arrays with "Title X" being the key.
The solution using array_intersect_key, array_intersect and array_column functions:
$result = [];
// getting concurrent 'titles'(by key)
$titles = array_intersect_key($excel_db_relation, $db_result);
foreach (array_intersect($titles, array_column($excel_arr, 1)) as $k => $v) {
$result[$v] = $db_result[$k];
}
print_r($result);
The output:
Array
(
[Title 1] => Cell 1 Value
[Title 2] => Cell 2 Value
[Title 3] => Cell 3 Value
)
Update:
Alternative approach to hold the order in which each value must be printed. Used functions: array_merge_recursive(to combine cell titles and values into separate groups) and array_column functions:
$result = [];
$bindings = array_column(array_merge_recursive($db_result, $excel_db_relation), 0, 1);
foreach (array_column($excel_arr, 1) as $title) {
if (isset($bindings[$title])) $result[$title] = $bindings[$title];
}
print_r($result);
The output:
Array
(
[Title 3] => Cell 3 Value
[Title 1] => Cell 1 Value
[Title 2] => Cell 2 Value
)
Try this:
$result = array_flip($excel_db_relation);
array_walk($result, function(&$value, $key) use ($db_result) {
$value = $db_result[$value];
});
var_dump($result);
But make sure that all keys exist beforehand.
This worked for me:
<?php
//...
usort($excel_arr, function ($a, $b) { return strnatcmp($a[0], $b[0]); });
$result = [];
// traverse the *title* column in the sorted $excel_arr
foreach (array_column($excel_arr, 1) as $a) {
// could use array_flip to speed up this test, though
// this can be problematic if the values aren't *good* array keys
$k = array_search($a, $excel_db_relation);
// if there is a key and it also exists in $db_result
if (false !== $k && array_key_exists($k, $db_result)) {
// assign it to the final result
$result[$a] = $db_result[$k];
}
}
print_r($result);

Unsetting element in array

I am trying to remove a key/value pair from an array but it does not seem to work. Basically, I make an API call which returns JSON. As such I do
$tempArray = json_decode($projects, true);
If I output $tempArray I see something like this
array:2 [
0 => array:9 [
"id" => 4
"name" => "Some Project Name"
"value" => "234"
"user_id" => "1"
"client_id" => "97"
"contact" => "Jane Berry"
]
1 => array:9 [
"id" => 3
"name" => "Another Project Name"
"value" => "6"
"user_id" => "1"
"client_id" => "97"
"contact" => "John Doe"
]
]
I essentially need to remove the value element so I do this
unset($tempArray['value']);
If I output $tempArray after the unset, it displays exactly the same as before, with the value element and value there.
What do I need to do to completely remove this from my array?
Thanks
unset will not look recursivly to sub-array to remove the key value. Only if you have at first level a key named value will be removed. In your array first level keys are: 0 and 1.
So to remove value from all sub-arrays you have to go throw all items from the array and unset it. You can do this with a simple foreach.
foreach($tempArray as $key => $data) {
unset($data['value']);
$tempArray[$key] = $data; //Overwrite old data with new with value unset.
}
Now you will not have value key in sub-array items.
As per my comment, you have no key called 'value' which is a top level key in your array. If you array looked like this:
$myArray = array(
"value" => "My Value to delete",
"anotherKey" => "hello world",
);
Then you could do unset($myArray['value']); and you would remove the key and value. In your case, the key you are looking for is nested under a numeric key [0] or [1]. You could reference these specifically like this:
unset($tempArray[0]['value']);
but what I imagine you are looking to achieve is to remove any trace of the key value from your array in which case you would be better off doing something like this:
foreach($tempArray as &$nestedArray){
unset($nestedArray['value']);
}
Note the & symbol before the $nestedArray. This means 'pass by value' and will actually update the $tempArray in a single line without the need for anything else.
Further Reading:
PHP Docs - Arrays
PHP Docs - Foreach loop
PHP Docs - Pass by reference

Take one array and combine it into another array

Hey Guys I have a quick question. I have an array that is as follows:
[0]=>
array(2) {
["id"]=>
string(3) "Prod ID"
["qty"]=>
string(1) "2"
}
Now this array has all of the orders from a given group of people. This means that product ID will be listed more then once.
I am trying to combine them and increment the qty so that I can pull a report against the top 5 products sold. But I am not sure how to accomplish this as I am new to arrays.
I tried putting it into a loop and setting it to a second array, then if the product ID matched one in the existing array, it would add the qty values together.
Any help would be much Appreciated.
Normally, what you do here is that you group them to another array and loop them using the id, making it a key. When a key is assigned, it is pushed inside normally, if it already exists, just add the existing quantity to the one on the current loop. Example:
$new_data = array();
foreach($data as $value) {
// simple initialization
if(!isset($new_data[$value['id']])) {
$new_data[$value['id']] = array('id' => $value['id'], 'qty' => 0);
}
// then sum up the quantity
$new_data[$value['id']]['qty'] += $value['qty'];
}
$new_data = array_values($new_data); // simple reindex
Then to get the top 5, sort it to descending first, get slice the array to get the 5.
usort($new_data, function($a, $b){
return $b['qty'] - $a['qty']; // sort descending
});
// get top 5
$top_5 = array_slice($new_data, 0, 5);
Use this:
foreach ($arr as $value)
$newArr[$value['id']] = (isset($newArr[$value['id']])) ? $newArr[$value['id']] + $value['qty'] : $value['qty'] ;
Here an example how you should do it:
$test = [
[
"id" => "1",
"qty" => "2"
],
[
"id" => "1",
"qty" => "2"
],
[
"id" => "2",
"qty" => "2"
],
[
"id" => "4",
"qty" => "1"
],
[
"id" => "2",
"qty" => "3"
],
[
"id" => "4",
"qty" => "1"
]
];
foreach ($test as $value)
$newArr[$value['id']] = (isset($newArr[$value['id']])) ? $newArr[$value['id']] + $value['qty'] : $value['qty'] ;
arsort($newArr);
print_r($newArr);
OUTPUT
Array
(
[2] => 5
[1] => 4
[4] => 2
)
Now you have an id as key and the sum of the qty related to this id as a value. It was sorted with arsort so you can treat the informations easily.

Categories