move a specific subarray to the top of a multidimensional array - php

I have an array of rows (from a mysql table)
And need to move to the top a subarray - i.e. a row - having id = $x
Tried a modified solution from here - without success
$st = $db->prepare("select id, nick from presto where id < 4");
$st->execute();
$rows = $st->fetchAll(PDO::FETCH_ASSOC);
print_r($rows);
result
Array ( [0] => Array ( [id] => 52 [nick] => 5fb63a1a8bcbf ) [1] => Array ( [id] => 54 [nick] => 5fb63a1a75171 ) [2] => Array ( [id] => 59 [nick] => 5fb63a1a91e68 ) )
$x = 54;
foreach($rows as $key => $val){
if($key['id'] == $x){ // line 155
unset($rows[$key]);
array_unshift($rows, $val);
}
}
and getting Warning - Trying to access array offset on value of type int on line 155
please help

$key on line 155 is the index/iteration/position in the array/foreach, which is an integer, not an array. $val is your data array from each iteration.
Try this.
$x = 54;
foreach($rows as $key => $val){
if($val['id'] === $x){ // line 155
unset($rows[$key]);
array_unshift($rows, $val);
}
}

Related

Looping through array and get non-repeating values

I have an array of elements which I queried from the mongoDB.
This array has the id of a device and value of this device's consumptions.
For example there are 3 different ids -> 18,5,3 and multiple mixed values.
// first record of 18 so get value.
$row[0]["id"] = 18;
$row[0]["value"] = 100;
// not first record of 18 so ignore and move to the next record
$row[1]["id"] = 18;
$row[1]["value"] = 40;
// first record of 5 so get value.
$row[2]["id"] = 5;
$row[2]["value"] = 20;
// not first record of 18 so ignore and move to the next record
$row[3]["id"] = 18;
$row[3]["value"] = 30;
// first record of 3 so get value.
$row[4]["id"] = 3;
$row[4]["value"] = 20;
//not first record of 5 so ignore and move to the next record**
$row[5]["id"] = 5;
$row[5]["value"] = 30;
// not first record of 18 so ignore and move to the next record
$row[6]["id"] = 18;
$row[6]["value"] = 10;
...
....
What I am trying to do is loop through this $row array and get the most recent value of the id.
For example in above example what I want to return is:
id value
18 100
5 20
3 20
How can I do that kind of logic?
It can be done in several ways. The easiest one is to use a foreach:
$result = array();
foreach ($row as $i) {
if (! array_key_exists($i['id'], $result)) {
$result[$i['id']] = $i['value'];
}
}
# Verify the result
print_r($result);
The output is:
Array
(
[18] => 100
[5] => 20
[3] => 20
)
The same processing, but using array_reduce():
$result = array_reduce(
$row,
function(array $c, array $i) {
if (! array_key_exists($i['id'], $c)) {
$c[$i['id']] = $i['value'];
}
return $c;
},
array()
);
If you want to keep only the first occurrence of each 'id' then just add the values to an aggregate array - but only if they haven't been added already. Then grab the values of the aggregate array.
https://tehplayground.com/NRvw9uJF615oeh6C - press Ctrl+Enter to run
$results = array();
foreach ($row as $r) {
$id = $r['id'];
if (! array_key_exists($id, $results)) {
$results[$id] = $r;
}
}
$results = array_values($results);
print_r($results);
Array
(
[0] => Array
(
[id] => 18
[value] => 100
)
[1] => Array
(
[id] => 5
[value] => 20
)
[2] => Array
(
[id] => 3
[value] => 20
)
)
Try this
$alreadyfound = []; // empty array
$result = [];
foreach ($row as $item)
{
if (in_array($item["id"], $alreadyfound))
continue;
$alreadyfound[] = $item["id"]; // add to array
$result[] = $item;
}
The result
Array
(
[0] => Array
(
[id] => 18
[value] => 100
)
[1] => Array
(
[id] => 5
[value] => 20
)
[2] => Array
(
[id] => 3
[value] => 20
)
)
The array_unique() function is exactly what you are looking at.
See the documentation here : array_unique() documentation
Using array_column with an index key will almost do it, but it will be in the reverse order, so you can reverse the input so that it works.
$result = array_column(array_reverse($row), 'value', 'id');

Find greatest value from json array in php

I'm using the following code to display the time for each character from a JSON. But the problem is there are repeated elements. I only want to select the highest value for each.
For example, highest value of s is 85, t is 84.
I tried the max() function, but only returning largest of all:
<?php
$speedArray = json_decode('[{"key":"e","time":35},{"key":"s","time":43},{"key":"t","time":39},{"key":"t","time":84},{"key":"s","time":85},{"key":"s","time":27},{"key":"t","time":80}]', true);
foreach ($speedArray as $timing) {
echo $timing['key'].$timing['time']."<br/>";
}
?>
First I would create a $key mapping and put all the values as array:
<?php
$speedArray = json_decode('[{"key":"e","time":35},{"key":"s","time":43},{"key":"t","time":39},{"key":"t","time":84},{"key":"s","time":85},{"key":"s","time":27},{"key":"t","time":80}]', true);
$keys = array();
foreach ($speedArray as $key) {
$keys[$key["key"]][] = $key["time"];
}
print_r($keys);
The output would be:
Array
(
[e] => Array
(
[0] => 35
)
[s] => Array
(
[0] => 43
[1] => 85
[2] => 27
)
[t] => Array
(
[0] => 39
[1] => 84
[2] => 80
)
)
Now it is easier to get the greatest of it. Using the max() function:
<?php
$speedArray = json_decode('[{"key":"e","time":35},{"key":"s","time":43},{"key":"t","time":39},{"key":"t","time":84},{"key":"s","time":85},{"key":"s","time":27},{"key":"t","time":80}]', true);
$keys = array();
foreach ($speedArray as $key) {
$keys[$key["key"]][] = $key["time"];
}
foreach ($keys as $key => $vals) {
echo "{$key}: " . max($vals) . "\n";
}
I get to this output:
e: 35
s: 85
t: 84
Demo: http://ideone.com/g4zULB
Getting max values for each key with a single loop and max function:
$speedArray = json_decode('[{"key":"e","time":35},{"key":"s","time":43},{"key":"t","time":39},{"key":"t","time":84},{"key":"s","time":85},{"key":"s","time":27},{"key":"t","time":80}]', true);
$result = [];
foreach ($speedArray as $v) {
(isset($result[$v['key']]))?
$result[$v['key']] = max($result[$v['key']], $v['time'])
: $result[$v['key']] = $v['time'];
}
print_r($result);
THe output:
Array
(
[e] => 35
[s] => 85
[t] => 84
)

Create an array from two array PHP

i have two arrays
$value_array = array('50','40','30','20','10');
$customer = array('300','200','100');
i want to distribute the value array to customers based on the value of customers that is taken as limit.adding values by checking it wont cross the limit that is 300 , 200 and 100.
but customer array not working one direction it should work first forward and then backward like that
i want to produce an array in form of
Array
(
[0] => Array
(
[0] => 50
)
[1] => Array
(
[0] => 40
[1] => 10
)
[2] => Array
(
[0] => 30
[1] => 20
)
)
After completing customer loop first time it should start from last to first. both array count will change , i mean count.
value array should check 50 -> 300 , 40->200, 30->100 then from last ie, 20 ->100, 10->200 etc.
I tried like
$i = 0;
while($i < count($customer)){
foreach($value_array as $k=>$value){
$v = 0;
if($value <= $customer[$i]){
$customer2[$i][] = $value;
unset($value_array[$k]);
$v = 1;
}
if($v ==1){
break;
}
}
//echo $i."<br/>";
if($i == (count($customer)-1) && (!empty($value_array))){
$i = 0;
$customer = array_reverse($customer, true);
}
$i++;
}
echo "<pre>";
print_r($customer2);
$valueArray = array('50','40','30','20','10','0','-11');
$customer = array('300','200','100');
function parse(array $valueArr, array $customerArr)
{
$customerCount = count($customerArr);
$chunkedValueArr = array_chunk($valueArr, $customerCount);
$temp = array_fill(0, $customerCount, array());
$i = 0;
foreach ($chunkedValueArr as $item) {
foreach ($item as $key => $value) {
$temp[$key][] = $value;
}
$temp = rotateArray($temp);
$i++;
}
// if $i is odd
if ($i & 1) {
$temp = rotateArray($temp);
}
return $temp;
}
function rotateArray(array $arr)
{
$rotatedArr = array();
//set the pointer to the last element and add it to the second array
array_push($rotatedArr, end($arr));
//while we have items, get the previous item and add it to the second array
for($i=0; $i<sizeof($arr)-1; $i++){
array_push($rotatedArr, prev($arr));
}
return $rotatedArr;
}
print_r(parse($valueArray, $customer));
returns:
Array
(
[0] => Array
(
[0] => 50
[1] => 0
[2] => -11
)
[1] => Array
(
[0] => 40
[1] => 10
)
[2] => Array
(
[0] => 30
[1] => 20
)
)

Associative index array to associative associative array

Problem
I have an array which is returned from PHPExcel via the following
<?php
require_once 'PHPExcel/Classes/PHPExcel/IOFactory.php';
$excelFile = "excel/1240.xlsx";
$objReader = PHPExcel_IOFactory::createReader('Excel2007');
$objPHPExcel = $objReader->load($excelFile);
foreach ($objPHPExcel->getWorksheetIterator() as $worksheet) {
$arrayData[$worksheet->getTitle()] = $worksheet->toArray();
}
print_r($arrayData);
?>
This returns:
Array
(
[Films] => Array
(
[0] => Array
(
[0] => Name
[1] => Rating
)
[1] => Array
(
[0] => Shawshank Redemption
[1] => 39
)
[2] => Array
(
[0] => A Clockwork Orange
[1] => 39
)
)
[Games] => Array
(
[0] => Array
(
[0] => Name
[1] => Rating
)
[1] => Array
(
[0] => F.E.A.R
[1] => 4
)
[2] => Array
(
[0] => World of Warcraft
[1] => 6
)
)
)
What I would like to have is
Array
(
[Films] => Array
(
[0] => Array
(
[Name] => Shawshank Redemption
[Rating] => 39
)
[1] => Array
(
[Name] => A Clockwork Orange
[Rating] => 39
)
)
[Games] => Array
(
[0] => Array
(
[Name] => F.E.A.R
[Rating] => 4
)
[1] => Array
(
[Name] => World of Warcraft
[Rating] => 6
)
)
)
The arrays names (Films, Games) are taken from the sheet name so the amount can be variable. The first sub-array will always contain the key names e.g. Films[0] and Games[0] and the amount of these can be varible. I (think I) know I will need to do something like below but I'm at a loss.
foreach ($arrayData as $value) {
foreach ($value as $rowKey => $rowValue) {
for ($i=0; $i <count($value) ; $i++) {
# code to add NAME[n] as keys
}
}
}
I have searched extensively here and else where if it is a duplicate I will remove it.
Thanks for any input
Try
$result= array();
foreach($arr as $key=>$value){
$keys = array_slice($value,0,1);
$values = array_slice($value,1);
foreach($values as $val){
$result[$key][] = array_combine($keys[0],$val);
}
}
See demo here
You may use nested array_map calls. Somehow like this:
$result = array_map(
function ($subarr) {
$names = array_shift($subarr);
return array_map(
function ($el) use ($names) {
return array_combine($names, $el);
},
$subarr
);
},
$array
);
Demo
Something like this should work:
$newArray = array();
foreach ($arrayData as $section => $list) {
$newArray[$section] = array();
$count = count($list);
for ($x = 1; $x < $count; $x++) {
$newArray[$section][] = array_combine($list[0], $list[$x]);
}
}
unset($arrayData, $section, $x);
Demo: http://ideone.com/ZmnFMM
Probably a little late answer, but it looks more like your tried solution
//Films,Games // Row Data
foreach ($arrayData as $type => $value)
{
$key1 = $value[0][0]; // Get the Name Key
$key2 = $value[0][1]; // Get the Rating Key
$count = count($value) - 1;
for ($i = 0; $i < $count; $i++)
{
/* Get the values from the i+1 row and put it in the ith row, with a set key */
$arrayData[$type][$i] = array(
$key1 => $value[$i + 1][0],
$key2 => $value[$i + 1][1],
);
}
unset($arrayData[$type][$count]); // Unset the last row since this will be repeated data
}
I think this will do:
foreach($arrayData as $key => $array){
for($i=0; $i<count($array[0]); $i++){
$indexes[$i]=$array[0][$i];
}
for($i=1; $i<count($array); $i++){
for($j=0; $j<count($array[$i]); $j++){
$temp_array[$indexes[$j]]=$array[$i][$j];
}
$new_array[$key][]=$temp_array;
}
}
print_r($new_array);
EDIT: tested and updated the code, works...

Counting an eliminating duplicate associative values in an array

I have the following issue, I have an array with the name $data
Within this array I have something like
[6] => Array
(
[code] => 642
[total] => 1708
)
[7] => Array
(
[code] => 642
[total] => 53
)
[8] => Array
(
[code] => 642
[total] => 1421
)
In some elements the code value is the same, now what I want to do is merge all the elements with the same code value together, and adding the totals together. I tried doing this in a foreach loop, but does not seem to work.
I do something like this
$old_lc = null;
$old_lcv = 0;
$count = 0;
$dd = null;
foreach($data as $d){
if($d['code'] == $old_lc){
$d['total'] = $d['total'] + $old_lcv;
$count--;
$dd[$count]['code'] = $d['code'];
$dd[$count]['total'] = $d['total'];
}else{
$dd[$count]['code'] = $d['code'];
$dd[$count]['total'] = $d['total'];
$count++;
}
$old_lc = $d['code'];
$old_lcv = $d['total'];
}
$data = $dd;
But this does not seem to work. Also I need the $data array to keep the keys, and should remain in the same format
$result = array();
foreach($ary as $elem) {
$code = $elem['code'];
$total = $elem['total'];
if(!isset($result[$code]))
$result[$code] = 0;
$result[$code] += $total;
}
This code translates the above array into an array of code => total.
$out = array();
foreach ($data as $k => $v) {
$out[$v['code']] += $v['total'];
}
It is worth noting that on certain settings this will generate a warning about undefined indexes. If this bothers you, you can use this alternate version:
$out = array();
foreach ($data as $k => $v) {
if (array_key_exists($v['code'], $out)) {
$out[$v['code']] += $v['total'];
} else {
$out[$v['code']] = $v['code'];
}
}
This turns it back into something like the original, if that's what you want:
$output = array();
foreach ($out as $code => $total) {
$output[] = array('code' => $code, 'total' => $total);
}
Note: the original keys of $data aren't maintained but it wasn't stated that this was a requirement. If it is, it needs to be specified how to reconstruct multiple elements that have the same code.
[6] => Array
(
[code] => 642
[total] => 1708
)
[7] => Array
(
[code] => 642
[total] => 53
)
[8] => Array
(
[code] => 642
[total] => 1421
)
$data_rec = array();
$data = array();
foreach($data_rec as $key=>$rec)
{
$data[$key]+= $rec[$key];
}
print_r($data);

Categories