Thank you for taking your time to look at this question.
I have a database entry that contains a serialized array (of multiple arrays). It might look like this:
Array 1
a:2:{
i:0;a:3:{s:11:"search_type";s:6:"owners";s:11:"search_text";s:4:"test";s:11:"search_name";s:4:"test";}
i:1;a:5:{s:8:"t_rating";s:3:"Yes";s:9:"t_ranking";s:3:"Yes";s:11:"search_type";s:8:"products";s:11:"search_text";s:5:"test2";s:11:"search_name";s:5:"test2";}
}
Then, I have another serialized array being passed that might look like this:
Array 2
a:2:{s:11:"search_type";s:6:"owners";s:11:"search_text";s:4:"test";}
Conditions
Array 1 can have any number of nested arrays (my example shows 2).
Array 2 is passed from a selector; which should loop Array 1 and remove it's associated nested array.
These arrays are being compared using PHP.
The Problem
The issue is that each array in Array 1 needs to first remove the "search_name" array key before making the comparison.
The "search_name" key from Array 1 should never be used for comparison. When the "search_name" key is removed; a valid comparison of the serialized arrays can then be made.
But, when this gets updated to the db; the non-removed arrays should still contain the "search_name" key. It only needs to be removed for comparison; then it's full array should be removed from Array 1.
My (Broken) Code
Here is what I currently have:
$search_array = unserialize($_POST['search_array']); // Serialized Array 2
$bm_adv_search = $query_adv_search[0]->bm_adv_search; // Serialized Array 1
$unser_array = unserialize($bm_adv_search); // Unserialize Array 1
// Unset search_name from each array in Array 1
foreach($unser_array as $key => $value) {
unset($unser_array[$key]['search_name']); // THIS IS THE PROBLEM AREA
}
// Unset Array 2 from Array 1
if(in_array($search_array, $unser_array)) {
if(($key = array_search($search_array, $unser_array)) !== false) {
unset($unser_array[$key]);
}
}
// Re-Serialize Array 1
$reser_array = serialize($unser_array);
// Update db with Array 1
.....
So when I update Array 1 to the db; the name field has been removed from all nested arrays, which when updated, excludes the "search_name".
I need the "search_name" to stay in each array from Array 1 when updated. I just need to remove it for comparison purposes... and then remove the nested array from Array 1.
The Idea
Basically, I am storing user saved bookmarks. When a user bookmarks an item; a serialized array gets added to Array 1. A user is prompted to enter a "Name" for the search bookmark; hence the "search_name" field.
When a user clicks to remove a bookmark; the "search_name" key is not available in the comparison array (Array 2). Array 1 should be looped for Array 2's existence (minus the "search_name" key)... and the entire matched array (including "search_name") should be unset.
Again, thank you for any time on this question. I really appreciate any assistance.
UPDATE
Got it working. Thanks Mikel!!
Here is the updated code:
$search_array = unserialize($_POST['search_array']); // Serialized Array 2
$bm_adv_search = $query_adv_search[0]->bm_adv_search; // Serialized Array 1
$unser_array = unserialize($bm_adv_search); // Unserialize Array 1
// Clone Array 1
$compare_array = $unser_array;
// Unset search_name from each array in cloned Array 1
foreach($compare_array as $key => $value) {
unset($compare_array[$key]['search_name']);
}
// Unset Array 2 from Array 1
if(in_array($search_array, $compare_array)) {
if(($key = array_search($search_array, $compare_array)) !== false) {
unset($unser_array[$key]);
}
}
// Re-Serialize Array 1
$reser_array = serialize($unser_array);
// Update db with Array 1
.....
Copy your "Array 1" to a temporary array for comparison, but do any true modifications to the main $unser_array.
Could be as simple as $compar_array = $unser_array and then modifying a few of the vars throughout the code.
You can then compare the two by array key, as they keys will be identical in the arrays. (you just created this copy)
Lemme know if you need any help!
Related
I've a multidimensional array of some arrays, in which the first values are ordered and included in a specific range.
Example:
A1=[[0,a],[3,b],[5,c],[6,a],[9,c]]
in which A1[i][0] are in range (0,10)
How can I obtain an array where, if the first value
(A1[i][0]) isn't a value present in the first array, e.g.
A1[i][0]==2
I insert an array with that value in the right position, with a specified second value (example A)?
Example of output i want:
A1=[[0,a],[1,A],[2,A],[3,b],[4,A],[5,c],[6,a],[7,A],[8,A],[9,c]]
This will help
$A1 = [[0,'a'],[3,'b'],[5,'c'],[6,'a'],[9,'c']];
foreach($A1 as $A2) $A3[] = $A2[0];//make a new array contain keys of the first array.
for($i=0;$i<=9;$i++){
if(!in_array($i, $A3)){
$A1[] = [$i, 'A']; //check if the key not exist, make a new array with key who does not exist.
}
}
asort($A1);//sort the new element inside the array
print_r($A1);
output is,
[[0,a],[1,A],[2,A],[3,b],[4,A],[5,c],[6,a],[7,A],[8,A],[9,c]]
I got values of column A and B from Excel by below php code
for($i=1;$i<=$arrayCount;$i++)
{
$col_A = array(trim($allDataInSheet [$i]["A"]));
$col_B =array(trim($allDataInSheet [$i]["B"]));
}
If 'A' has 44 variable names and 'B' has 44 values.
In this scenario,How can I assign the values of 'B' to the variable names of 'A'
Please help me to solve this
Arrays in PHP can take on two different key-types and they can mix and match. Indexed by number and indexed by string. And an array can contain any value, including an array of values. This means that you can create an array that uses the names in Array A as the keys and the values in Array B as the values for those keys.
$columns = [];
// Arrays start at 0, but since these came from excel 0 is the column header.
// You want to stop 1 entry before the count of your array. Since arrays are 0 indexed, the array count is 1 larger than the last index.
for($i=1;$i<=$arrayCount-1;$i++)
{
$a = trim($allDataInSheet [$i]["A"]);
$b = trim($allDataInSheet [$i]["B"]);
// You don't need to specify the Array constructor anymore.
// You can just use brackets to create a new array.
// Not sure if you still want these, but I left them for you.
$col_A = [$a];
$col_B = [$b];
// Assign the values of B to columns in A
if(!isset($columns[$a]) {
$columns[$a] = $b;
} else {
// Debugging message - Tried to set two values to the same name.
}
}
// Do stuff with $columns
// $columns["a"] == "b"
Above, you can see that since $allDataInSheet[$i]["A"] is the string we want, we can just use that value as our key and its matching entry in B as the value for that key.
Notice how we don't let a value get added to the array if we already have that name set. If you want $columns[$a] to be an array of values, you can change it to look like this:
if(!isset($columns[$a]){
// If we don't have an entry for $columns[$a] create an array here to hold the values for possible $b's.
$columns[$a] = [];
}
// Add $b to the $columns[$a] array.
$columns[$a][] = $b;
That will treat the $columns array as an array of arrays. Meaning that each position can hold multiple values. So, we turn it into an array and just add the $b value to that position. If we come across that $a value again, we'll see that we already have that position set and we just use the array that's already there.
Notice - we do an isset check instead of an empty check because if 'b' was actually " " or false or 0 or for some strange reason, $columns[$a] doesn't change from an empty array to an array with something in it, than we don't want to erase the value that's already there.
Good Luck!
Question has been updated to clarify
For simple arrays, I find it convenient to use $arr[$key]++ to either populate a new element or increment an existing element. For example, counting the number of fruits, $arr['apple']++ will create the array element $arr('apple'=>1) the first time "apple" is encountered. Subsequent iterations will merely increment the value for "apple". There is no need to add code to check to see if the key "apple" already exists.
I am populating an array of arrays, and want to achieve a similar "one-liner" as in the example above in an element of the nested array.
$stats is the array. Each element in $stats is another array with 2 keys ("name" and "count")
I want to be able to push an array into $stats - if the key already exists, merely increment the "count" value. If it doesn't exist, create a new element array and set the count to 1. And doing this in one line, just like the example above for a simple array.
In code, this would look something like (but does not work):
$stats[$key] = array('name'=>$name,'count'=>++);
or
$stats[$key] = array('name'=>$name,++);
Looking for ideas on how to achieve this without the need to check if the element already exists.
Background:
I am cycling through an array of objects, looking at the "data" element in each one. Here is a snip from the array:
[1] => stdClass Object
(
[to] => stdClass Object
(
[data] => Array
(
[0] => stdClass Object
(
[name] => foobar
[id] => 1234
)
)
)
I would like to count the occurrences of "id" and correlate it to "name". ("id" and "name" are unique combinations - ex. name="foobar" will always have an id=1234)
i.e.
id name count
1234 foobar 55
6789 raboof 99
I'm using an array of arrays at the moment, $stats, to capture the information (I am def. open to other implementations. I looked into array_unique but my original data is deep inside arrays & objects).
The first time I encounter "id" (ex. 1234), I'll create a new array in $stats, and set the count to 1. For subsequent hits (ex: id=1234), I just want to increment count.
For one dimensional arrays, $arr[$obj->id]++ works fine, but I can't figure out how to push/increment for array of arrays. How can I push/increment in one line for multi-dimensional arrays?
Thanks in advance.
$stats = array();
foreach ($dataArray as $element) {
$obj = $element->to->data[0];
// this next line does not meet my needs, it's just to demonstrate the structure of the array
$stats[$obj->id] = array('name'=>$obj->name,'count'=>1);
// this next line obviously does not work, it's what I need to get working
$stats[$obj->id] = array('name'=>$obj->name,'count'=>++);
}
Try checking to see if your array has that value populated, if it's populated then build on that value, otherwise set a default value.
$stats = array();
foreach ($dataArray as $element) {
$obj = $element->to->data[0];
if (!isset($stats[$obj->id])) { // conditionally create array
$stats[$obj->id] = array('name'=>$obj->name,'count'=> 0);
}
$stats[$obj->id]['count']++; // increment count
}
$obj = $element->to->data is again an array. If I understand your question correctly, you would want to loop through $element->to->data as well. So your code now becomes:
$stats = array();
foreach ($dataArray as $element) {
$toArray = $element->to->data[0];
foreach($toArray as $toElement) {
// check if the key was already created or not
if(isset($stats[$toElement->id])) {
$stats[$toElement->id]['count']++;
}
else {
$stats[$toElement->id] = array('name'=>$toArray->name,'count'=>1);
}
}
}
Update:
Considering performance benchmarks, isset() is lot more faster than array_key_exists (but it returns false even if the value is null! In that case consider using isset() || array_key exists() together.
Reference: http://php.net/manual/en/function.array-key-exists.php#107786
I have an array that is associative that I have decoded from a json json_decode second value true and looks like
Array (
[test] => Array
(
[start] => 1358766000
[end] => 1358775000
[start_day] => 21
[end_day] => 21
)
)
But for some reason when I do $array[0] I get null? How can I get the array by index? Not by key name?
array_values() will give you all the values in an array with keys renumbered from 0.
The first level of the array is not numerical, it's an associative array. You need to do:
$array['test']['start']
Alternatively, to get the first element:
reset($array);
$first_key = key($array);
print_r($array[$first_key]);
You could use current.
$first = current($array); // get the first element (in your case, 'test')
var_dump($first);
This is by design . . . your JSON used a key (apparently test), which contained a JSON object. The keys are preserved when you do a json_decode. You can't access by index, though you could loop through the whole thing using a foreach.
From your comment, it sounds like you want to access previous and next elements from an associative array. I don't know a way to do this directly, but a hackish way would be as follows:
$testArr = array('a'=>'10', 'b'=>'2', 'c'=>'4');
// get numeric index of the element of interest
$keys = array_keys($testArr);
$i = array_search('b', $keys);
// get key of next element
$nextElementKey = $keys[$i+1];
// next element value
$nextElementValue = $testArry[$nextElementKey];
// get key of previous element
$prevElementKey = $keys[$i-1];
// prev value
$[prevElementValue = $testArry[$prevElementKey];
You'd probably want to add some error checking around the previous and next key calculations to handle the first and last values.
If you don't care about the data in the key, Ignacio's solution using array_keys is much more efficient.
I have a function that has to accept an array of points, or an array of array of points (a 2 or 3 dimensional array). I'm looking for an reliable way to detect whether it has 2 or 3 levels. The thing is, I cannot count on the keys of the arrays to do the checking, so this wont work:
$levels = isset($array[0][0]) && is_array($array[0][0]) ? 3 : 2;
..as the first key might not be 0. It usually is, but I don't want to rely on this. And anyways, it's an crappy and a close minded way to do that. Optimally, I would like to check for any number of levels without having to loop through the whole array.
Here's what the arrays might look like:
array(5) {
[2] => array(2) {
[x] => 3
[y] => 6
}
[3] => array(2) {
[x] => 4
[y] => 8
}
...
And a three dimensional array would contain these arrays.
Some notes:
The arrays are large, so completely looping through the arrays is not a very good option
The arrays are numerically and sequentially indexed (with the exception of the last level, which has x and y)
The array keys might or might not start from 0
While writing this, I came up with a solution that might be feasible; a recursive function that checks the first item of an array, if it is, then call itself on the newly found array etc.
Are there any better, cleaner ideas? Bonus points for supporting arrays that might have both scalar values and arrays (eg. the first item of an array might be a string, but the next is an array).
If you expect a complete array or a complete array of arrays then you could try:-
if (isset $points[0][0][0])
If however your array is sparse its more difficult.
The basic problem is that a php "array" is actually a one dimensional hash. The trick being that a value can be another "array". So you need to access to second level to determine whether its a value or an array.
Again if you expect a given array to contain only point values, or only other arrays you only need to check one entry so:
if ( is_array(current(current($points))) )
Should get you what you want: the current() function returns the current array pointer (which defaults to the first - so it will always be set to something), so the inside current($points) would get you $points[0] or the first entry with an actual value, likwise the outside current will get you something like $points[0][0].
I don't see how you could do this without at least iterating through the array. The simple fact is that any one of the elements in your array could have an additional level. As a result, every element needs to be tested.
That being said, you can still use recursion to improve your code a bit:
/**
* Determine the maximum depth of an array.
* #param $input The object to test. Might be an array, or might be an int (or
* any other object).
* #param $startDepth The starting depth. Will be added as an offset to the
* result.
* #return The depth of the array, plus any initial offset specified in
* $startDepth.
*/
function testDepth($input, $startDepth = 0) {
if (is_array($input)) {
$max = $startDepth;
foreach ($input as $i) {
// Check what the depth of the given element is
$result = testDepth($i, $startDepth + 1);
// We only care about the maximum value
if ($result > $max) {
$max = $result;
}
}
return $max;
} else {
// This isn't an array, so it's assumed not to be a container.
// This doesn't add any depth to the parent array, so just return $startDepth
return $startDepth;
}
}
testDepth($array);
$levels = is_array(current(current($array))) ? 3 : 2;