Array index stuck at [0] - php

I am trying to create an array out of looped data. The variables contain looped data. All works fine, but when array is outputted, the index gets stuck at 0 and doesn't move up from 0 to 1 etc. I wonder what the problem is and how I can get this fixed.
Thanks.
$productinfo = array(
array(
"Productname" => "$productname",
"StarRating" => "$starrating",
"AddedValue" => "$addedvalue",
"ProductImage" => "$image",
"TotalPrice" => "$totalprice",
"ProductLink" => "$link" )
);
$productinfojson= json_encode($productinfo);
$output = json_decode($productinfojson, TRUE);
echo "<pre>";
print_r( $output );
echo "</pre>";
The above outputs:
Array
(
[0] => Array
(
[Procuctname] => Pencil Stack
[StarRating] => 3
[AddedValue] => Free Delivery
[ProductImage] =>
[TotalPrice] => 5.50
[ProductLink] => http://---.net/product
)
)
Array
(
[0] => Array
(
[Procuctname] => Block Bundle
[StarRating] => 4
[AddedValue] => Free Delivery
[ProductImage] =>
[TotalPrice] => 15
[ProductLink] => http://---.net/product
)
)
UPDATE if only one array is used.
code:
$productinfo = array(
"Productname" => "$productname",
"StarRating" => "$starrating",
"AddedValue" => "$addedvalue",
"ProductImage" => "$image",
"TotalPrice" => "$totalprice",
"ProductLink" => "$link" );
OUTPUT
Array
(
[Procuctname] => Pencil Stack
[StarRating] => 3
[AddedValue] => Free Delivery
[ProductImage] =>
[TotalPrice] => 5.50
[ProductLink] => http://---.net/product
)
Array
(
[Procuctname] => Block Bundle
[StarRating] => 4
[AddedValue] => Free Delivery
[ProductImage] =>
[TotalPrice] => 15
[ProductLink] => http://---.net/product
)

The issue stems straight from your array creation. There doesn't seem to be a loop anywhere in your code either....
Anyways, lets sort out your array creation. I assume you're getting the data from a database/data source and assigning it to variables, inputting it into an array? Well the way you currently have it, it's overwriting the first index element in the array.
Disclaimer: The below is pseudo code, until you update with your actual loop code..
$productinfo = array();
while($row = FETCH_DATA_FROM_SQL()) {
// assign it to variables here...?
$productinfo[] = array(
"Productname" => "$productname",
"StarRating" => "$starrating",
"AddedValue" => "$addedvalue",
"ProductImage" => "$image",
"TotalPrice" => "$totalprice",
"ProductLink" => "$link"
);
}
That will add each element to the new $productinfo array and you should be able to loop through the elements correctly.
One more thing to note, you're decoding your json like this:
$output = json_decode($productinfojson, TRUE);
That second parameter (TRUE), turns it into an associative array, not an object. So when you loop it as an object like below:
foreach($response->products->product as $product) {...
It isn't going to work. If you want it as an object, remove the second parameter (TRUE), otherwise loop it as an array:
foreach($response['products']['product'] as $product) {...

Related

Remove all duplicate data from a multi-dimensional array [duplicate]

This question already has answers here:
Filter/Remove rows where column value is found more than once in a multidimensional array
(4 answers)
Closed 9 months ago.
I'm trying to remove all keys with repeated numbers, I've tried some solutions posted here like the one I'm using in my script but none of it worked for my purpose.
This is my array:
There are at least 4 card IDs repeated.
Array
(
[0] => Array
(
[id_card] => 11883834
[type] => 1
[registed] => 1547610891
)
[1] => Array
(
[id_card] => 20311077
[type] => 1
[registed] => 1547610891
)
[2] => Array
(
[id_card] => 16187903
[type] => 3
[registed] => 1547610891
)
[3] => Array
(
[id_card] => 16354099
[type] => 1
[registed] => 1547610891
)
[4] => Array
(
[id_card] => 21133393
[type] => 4
[registed] => 1547610891
)
[5] => Array
(
[id_card] => 15452852
[type] => 2
[registed] => 1547610891
)
[6] => Array
(
[id_card] => 19775869
[type] => 2
[registed] => 1547610891
)
[7] => Array
(
[id_card] => 20311077
[type] => 1
[registed] => 1547610891
)
[8] => Array
(
[id_card] => 21133393
[type] => 4
[registed] => 1547610891
)
[9] => Array
(
[id_card] => 11883834
[type] => 1
[registed] => 1547610891
)
)
1
At the moment I have something like this:
<?php
$array_data = array_map('unserialize', array_unique(array_map('serialize', $myArray)));
echo '<pre>';
print_r($array_data);
echo '</pre>';
?>
With only 10 keys is working perfectly, but when it goes through this with, for example, 50, 100 keys, no longer works.
Any help appreciated.
So the issue here is that the array_unique solutions expect the entire value to be equivalent - they don't just compare based on your ID field.
Instead, you probably want to loop through the array and keep track of which IDs you've seen, and only take those elements for which you haven't seen the ID before.
function filter_duplicate_id_cards($data) {
$seen = array(); // To keep track of the IDs we've seen
$filtered = array(); // Will hold the result
foreach($data as $item) {
if(array_key_exists($item['id_card'], $seen)) {
// We already encountered this id card before.
continue;
}
// Never-before seen id card, append it to the result and set the key in $seen
$filtered[] = $item;
$seen[$item['id_card']] = TRUE;
}
return $filtered;
}
Note that this uses the map form of a PHP array, rather than just appending seen IDs to the list form and using something like in_array to check if we've seen the key. That's important for performance reasons, especially if we're going to be working on large datasets - in_array is O(n) with the # of items in the array whereas array_key_exists is O(1).
A more generic version of this function would look like this:
function filter_duplicate_field($data, $field) {
$seen = array(); // To keep track of the keys we've seen
$filtered = array(); // Will hold the result
foreach($data as $item) {
if(array_key_exists($item[$field], $seen)) {
// We already encountered this key before.
continue;
}
// Never-before seen key, append it to the result and set the key in $seen
$filtered[] = $item;
$seen[$item[$field]] = TRUE;
}
return $filtered;
}
You could then call it like $result = filter_duplicate_field($data, 'id_card');.
This doesn't preserve the original input order, but because the data is indexed so I'll assume that that doesn't matter.
With just 3 calls in a one-liner, you assign temporary associative keys from back to front to eliminate latter duplicates (because php does not permit duplicate keys), then optionally remove the temporary keys with array_values(). No iterated function calls. No lookup arrays.
Code: (Demo)
$array = [
['id_card' => 11883834, 'type' => 1, 'registed' => 1547610891],
['id_card' => 20311077, 'type' => 1, 'registed' => 1547610891],
['id_card' => 16187903, 'type' => 3, 'registed' => 1547610891],
['id_card' => 16354099, 'type' => 1, 'registed' => 1547610891],
['id_card' => 21133393, 'type' => 4, 'registed' => 1547610891],
['id_card' => 15452852, 'type' => 2, 'registed' => 1547610891],
['id_card' => 19775869, 'type' => 2, 'registed' => 1547610891],
['id_card' => 20311077, 'type' => 1, 'registed' => 1547610891],
['id_card' => 21133393, 'type' => 4, 'registed' => 1547610891],
['id_card' => 11883834, 'type' => 1, 'registed' => 1547610891]
];
var_export(array_values(array_column(array_reverse($array), null, 'id_card')));
If you change you mind about wanting to keep the first occurrence, you can remove array_reverse(). If the first level keys are irrelevant in the output, you can remove array_values(). These changes would allow the solution to be a one function call task.
p.s. "registered"

PHP search JSON without looping

I have a large JSON array which is the result of querying the API of an Icinga2 monitoring system.
I have used json_decode like this in my code to decode it:
$response = json_decode($array, true);
and I can see the output looks like this:
Array
(
[results] => Array
(
[0] => Array
(
[attrs] => Array
(
[__name] => HOSTNAME0
[acknowledgement] => 0
[acknowledgement_expiry] => 0
...
...
[state] => 0
[state_type] => 1
[meta] => Array
(
)
[name] => HOSTNAME0
[type] => Host
)
[1] => Array
(
[attrs] => Array
(
[__name] => HOSTNAME1
[acknowledgement] => 0
[acknowledgement_expiry] => 0
...
...
[state] => 0
[state_type] => 1
[meta] => Array
(
)
[name] => HOSTNAME1
[type] => Host
)
There are 400 Records in total and it's quite a complex structure but the only bits I am really interested in are the name and state fields.
Basically my script has a list of 150 hostnames from another source and what I want to do is for each hostname, search for it in the array and return the value of the state field for that host.
So far I've been struggling to do this without looping through the entire array for each of the 150 hostnames. There must be a more efficient way to do a lookup in the array based on a hostname and return a single value but I can't figure it out.
Given, the name field has no logical sorting inside the json result, there is no way to look at least once at each element. If they are sorted alphabetical, you could use a simple binary search, which would give you the result in O(log(n)).
The other thing is, if you have to search for multiple names, you could put them inside an name assiciated array. This way, you only have an initial overhead of O(n) building the list and each following search would return you the state on O(1).
// building the array
$states = [];
foreach ($items as $item) {
$states[$item['name']] = $item['state'];
}
looking for HOSTNAME1
$state = $states['HOSTNAME1'];
I'm hoping that I've got the source data array in the correct layout as the format was a bit confusing from the original question. But the main idea is to use array_column to extract the "attrs" and key the result by the "name" element of this array.
$response = Array(
"results" => Array(
0 => Array(
"attrs" => Array(
"__name" => "HOSTNAME0",
"acknowledgement" => 0,
"acknowledgement_expiry" => 0,
"state" => 0,
"state_type" => 1
),
"name" => "HOSTNAME0",
"type" => "Host"
),
1 => Array(
"attrs" => Array(
"__name" => "HOSTNAME1",
"acknowledgement" => 0,
"acknowledgement_expiry" => 0,
"state" => 2,
"state_type" => 1
),
"name" => "HOSTNAME1",
"type" => "Host1"
)
)
);
$extract = array_column($response["results"], "attrs", "name");
print_r($extract);
With the sample data, this gives...
Array
(
[HOSTNAME0] => Array
(
[__name] => HOSTNAME0
[acknowledgement] => 0
[acknowledgement_expiry] => 0
[state] => 0
[state_type] => 1
)
[HOSTNAME1] => Array
(
[__name] => HOSTNAME1
[acknowledgement] => 0
[acknowledgement_expiry] => 0
[state] => 2
[state_type] => 1
)
)
So to find any server by name, you'd use
echo "HOSTNAME1=".$extract["HOSTNAME1"]["state"].PHP_EOL;
If you only wanted the state field (as you asked for) and wanted to simplify the array, you can then use...
array_walk($extract, function(&$data) {$data=$data["state"];});
print_r($extract);
The array_walk() goes through the array and just copies the state field to be the entry, so the result of this is...
Array
(
[HOSTNAME0] => 0
[HOSTNAME1] => 2
)
So now you just do...
echo "HOSTNAME1=".$extract["HOSTNAME1"].PHP_EOL;

Multidimensionnal ARRAY - 3 and 4 levels

I have this 3 and 4 multidimensionnal array ($response) which I need to "extract" some values.
Array (
[status] => 200
[response] => Array (
[api_id] => 38229dd9-8c52-11e5-80f6-22000afd0039
[meta] => Array (
[limit] => 20
[next] => /v1/Account/xxx/Call/?limit=20&offset=20
[offset] => 0
[previous] =>
[total_count] => 57 )
[objects] => Array (
[0] => Array (
[answer_time] => 2015-11-13 18:36:19+01:00
[bill_duration] => 10
[billed_duration] => 60
[call_direction] => inbound
[call_duration] => 10
[call_uuid] => dcd94e59-8775-4c81-a4b1-cd5d41d630c6
[end_time] => 2015-11-13 18:36:29+01:00
[from_number] => 3300000000
[initiation_time] => 2015-11-13 18:36:18+01:00
[parent_call_uuid] =>
[resource_uri] => /v1/Account/xxx/Call/dcd94e59-8775-4c81-a4b1-cd5d41d630c6/
[to_number] => 3300000000
[total_amount] => 0.00500
[total_rate] => 0.00500 )
[1] => Array (
[answer_time] => 2015-11-13 15:52:01+01:00 [
bill_duration] => 48
[billed_duration] => 60
[call_direction] => inbound
[call_duration] => 48
[call_uuid] => b2d3de5d-a047-4409-9f7a-825373c38f0a
[end_time] => 2015-11-13 15:52:48+01:00
[from_number] => 3300000000
[initiation_time] => 2015-11-13 15:52:00+01:00
[parent_call_uuid] =>
[resource_uri] => /v1/Account/xxx/Call/b2d3de5d-a047-4409-9f7a-825373c38f0a/
[to_number] => 3300000000
[total_amount] => 0.00500
[total_rate] => 0.00500 )
...
In the [meta] array, I need the [total_count] value and for the [object] array, I'd like to get all the values to disaply them in a row (each object is a new row).
I have tried foreach within foreach or access datas with $response[0][0][0] but nothing do.
If someone could lead me to the solution...
Thanks a lot !!
You can access the meta array through $response['response']['meta']. As you can see from your array, both response and meta are keys, and so is total_count. Hence, accessing total count is done by $response['response']['meta']['total_count'].
To then loop through all your objects, simply do
foreach ($response['response']['objects'] as $object) {
print_r($object);
}
You can also access every attribute of the object individually by using the array keys:
foreach ($response['response']['objects'] as $object) {
echo $object['answer_time'];
echo $object['bill_duration'];
echo $object['billed_duration'];
echo $object['call_direction'];
echo $object['call_duration'];
echo $object['call_uuid'];
echo $object['end_time'];
echo $object['from_number'];
echo $object['initiation_time'];
echo $object['parent_call_uuid'];
echo $object['resource_uri'];
echo $object['to_number'];
echo $object['total_amount'];
echo $object['total_rate'];
}
First, to verify, if $array is the name of your array:
$response = $array["response"];
In the [meta] array, I need the [total_count] value
echo $response["meta"]["total_count"];
and for the [object] array, I'd like to get all the values to disaply them in a row (each object is a new row).
Use a foreach() function for all the objects:
foreach($response["objects"] as $object){
print_r($object);
}
You can use the "count" function with "COUNT_RECURSIVE" flag. It counts all the items inside the 'mixed' var. It counts parent element too.
count($array['objects'],COUNT_RECURSIVE);
example
$cibo = array(
'frutta' => array('arancia', 'banana', 'mela'),
'verdura' => array('carota', 'zucchina', 'piselli')
);
echo count($cibo,COUNT_RECURSIVE); // output 8

Cakephp using Set class to fetch data with key starting at zero

I'm using Set class of Cakephp to format the find returned array but cannot seem to find a way to get the counter starting at zero and auto-increment for array keys so it is like
[0] => 3
[1] => 6
[2] => 12
I'm currently using below query to get the data from my HasAndBelongsToMany table.
$interest_ids = Set::combine($this->User->Interestsub->find('threaded', array
(
'conditions' => array
(
'Interestsub.name' => $interests
),
//'fields' => array('Interestsub.id'),
'recursive' => -1
)
),
'{n}.Interestsub.id',
'{n}.Interestsub.id'
);
The reason why I need this is that I'm currently trying to get the returned array as part of bigger parent array preparing to be saved for SaveAll function. To be formatted properly, I need below nested array coming out:
[0] => Array
(
[interestssub_id] => 12
[user_id] => 2
)
[1] => Array
(
[interestssub_id] => 22
[user_id] => 2
)
[2] => Array
(
[interestssub_id] => 32
[user_id] => 2
)
Is there a way we can use Combine class to format the returned array like above?
There's no real reason to use the Set class in this case. Just use good old fashioned php:
$threaded = $this->User->Interestsub->find('threaded', array(
'conditions' => array(
'Interestsub.name' => $interests
),
'recursive' => -1
));
$interest_ids = array();
foreach ($threaded as $thread) {
$interest_ids[] = array(
'interestssub_id' => $thread['Interestsub.id'],
'interestssub_id' => $thread['Interestsub.user_id']
);
}

Creating arrays dynamically using PHP

Hey folks, please lend a hand to a PHP beginner. I'm trying to put a load of dynamically created variabled into an array to re-read later, reason is a SOAP message sent is a mess and im trying to create a less complicated array:
$placea = "place a";
$placeb = "place b";
$myarray = array();
echo "<pre>";
print_r($myarray);
echo "</pre>";
what i want to be able to do:
Array
(
[0] => [Place A] => Array
(
[0] => [Accommodation] => Array
(
[RoomId] => 001
[RoomAvail] => true
[Date] => 12.04.2011
)
[1] => [Accommodation] => Array
(
[RoomId] => 002
[RoomAvail] => true
[Date] => 12.04.2011
)
) Array
(
[1] => [Place B] => Array
(
[0] => [Accommodation] => Array
(
[RoomId] => 101
[RoomAvail] => true
[Date] => 12.04.2011
)
[1] => [Accommodation] => Array
(
[RoomId] => 102
[RoomAvail] => true
[Date] => 12.04.2011
)
)
)
how would i write that out in php? sorry if its bleek and/or the array structure is incorrect
So you just need to use the array initializer repetitively.
If you want to initialize an array in PHP with some values, say 1 through 4, you make a call like:
$foo = array(1, 2, 3, 4);
And if you want to make an associative array, where you store some key/value pairs, you make a call like:
$foo = array('key' => 'value', 'other key' => 'other value');
But you can of course nest calls, and mix and match layers of associative and non associative arrays to achieve something like your example, e.g.:
$foo = array(
'Place A' => array(
// note use of first array on the next line is
// to generate structure like [0] => 'Accomodation' => ...
array('Accomodation' => array(
'RoomId' => '001',
'RoomAvail' => true,
'Date' => '12.04.2011')
)),
array('Accomodation' => array(
'RoomId' => '002',
'RoomAvail' => true,
'Date' => '12.04.2011')
))
),
'Place B' => array(
array('Accomodation' => array(
'RoomId' => '101',
'RoomAvail' => true,
'Date' => '12.04.2011')
)),
array('Accomodation' => array(
'RoomId' => '102',
'RoomAvail' => true,
'Date' => '12.04.2011')
))
)
);
This will very nearly produce what you're looking for, to make it replicate exactly what you have you would wrap each 'Place A' with an array and each "place" would get its own assignment to some variable $foo (I assumed this wasn't actually what you wanted and wrote something maybe slightly more intuitive).
If you want to have a 'less complicated' array, you have a two arrays, one fore place a and one for place b and then merge them using array_merger() http://www.php.net/manual/en/function.array-merge.php.
Study up on the array functions control structures in the manual. Many different ways of achieving bloated arrays uglying up your code.
This would dynamically create an array.
foreach($soapResponse as $key1 => $value1){
foreach($value as $key2 => $value2){
// $key1 = Place A or B
// value1 = array of values
$arrayResponse[$key1][$key2] = $value2;
}
}

Categories