Get previous and next values in array - php

I have array, for example:
<?php
$array = array(
0 => array(
'subject' => 'Stackoverflow',
'body' => '',
'name' => 'php'
),
1 => array(
'subject' => 'Test',
'body' => 'Wayne',
'name' => ''
),
2 => array(
'subject' => '',
'body' => 'this is ok',
'name' => ''
),
3 => array(
'subject' => 'cnn',
'body' => 'Google',
'name' => 'private'
),
4 => array(
'subject' => 'code',
'body' => '',
'name' => '7777'
)
);
And i would like get subject, body and name for key 2 and if key not exist then this should get from previous and next (separate function) values.
For example if i want get value from 2 key:
function getCurrentOrPrevious(2);
should return:
array(
'subject' => 'Test', //from [1]
'body' => 'this is ok', //from [2] - current and exist
'name' => 'php' //from [0] - in from [2] and [1] not exist
)
function getCurrentOrNext(2);
should return:
array(
'subject' => 'cnn', //from [3]
'body' => 'this is ok', //from [2] - current
'name' => 'php' //from [3]
)
How is the best way for this? Are there any functions in PHP for such operations?
LIVE

Assuming, you fill your array similar to $array[] = $value; [i.e. that you have consecutive numeric keys starting from zero]:
## $array is the array to take values from, $key is the target key
## $fields are required fields
function getCurrentOrPrevious($array, $key, $fields) {
if ($key < 0) return null;
$output = array();
foreach ($fields as $field) {
for ($i = $key; $i >= 0; $i--) {
if (!empty($array[$i][$field])) {
$output[$field] = $array[$i][$field];
break;
}
}
return $output;
}
Use as follows:
$my_values = getCurrentOrPrevious($array, 12, array('subject', 'body', 'name'));

I guess you could use empty() function of php to check. Also you should think about how far that function shell go?
What if [3] (next) also has an empty value at the same position
What if previous index is <0?
UPDATE
function getCurrOrNext($array, $index){
$keys = array_keys($array[$index]);
foreach($keys AS $key){
if($array[$index][$key] == "") {
$array[$index][$key] = (!empty($array[$index+1]) && !empty($array[$index+1][$key])?$array[$index+1][$key]:null);
}
}
return $array;
}
I guess something like this

function getCurrentOrPrev($array, $key) {
while(key($array)!==$key) next($array); //move internal pointer to required position first
$result = current($array);
//loop is going to execute as long as at least one of elements is empty and we didn't get to beginning of array yet
while((empty($result['subject'])
|| empty($result['body'])
|| empty($result['name']))
&& prev($array)!==false) {
$c = current($array);
//replace empty elements with values of current element
$result['subject'] = empty($result['subject']) ? $c['subject'] : '';
$result['body'] = empty($result['body']) ? $c['body'] : '';
$result['name'] = empty($result['name']) ? $c['name'] : '';
}
return $result;
}
For function with next simply replace prev() method with next(), or to minimize code duplication You may introduce third parameter and call correct method based on its value.
This method doesn't care about values of the key other but the key specified in parameter.
You may have mixed literal and numeric indexes.

Related

Array Elements inconsistently getting added in PHP with array += array

This might be a stupid question, but I am having trouble figuring out why this does not always work. I initialize an array and then pass through a number of if statements that add another element to the array. This seems to work most of the time, but sometimes an element does not get added even though the if statement is true. Here is some code:
$data = array ("command" => "/order/list", "account_id" => Config::get('DEFAULT_ACCOUNT_ID'));
if (isset($post['data-mrn']) && $post['data-mrn'] != '' ) {
$data += array("filter.patientid.equals" => $post['data-mrn']);
}
if (isset($post['data-name']) && $post['data-name'] != '' ) {
$data += array("filter.patient_name.like" => '');
}
if (isset($post['data-accession']) && $post['data-accession'] != '' ) {
$data += array("filter.accession_number.equals" =>$post['data-accession']);
}
if (isset($post['data-description']) && $post['data-description'] != '') {
$data += array("filter.customfield-421250f4-ea28-42b2-b53d-06ba84f16d36.like" => 'xxx');
}
if (isset($post['data-modality']) && $post['data-modality'] != '' ) {
$data += array("filter.customfield-421250f4-ea28-42b2-b53d-06ba84f16d36.like" => 'xxx');
}
if (isset($post['data-status']) && $post['data-status'] != '') {
$data += array("filter.customfield-421250f4-ea28-42b2-b53d-06ba84f16d36.like" => 'xxx');
}
if (isset($post['data-date']) && $post['data-date'] != '' ) {
$post['data-date'] = str_replace("-","",$post['data-date']);
$data += array("filter.customfield-421250f4-ea28-42b2-b53d-06ba84f16d36.like" => 'xxx');
print_r($data );
}
If I pass in an mrn, an accession_number and a status and a date, I get:
Array (
[command] => /order/list [account_id] => xxx
[filter.patientid.equals] => xxx
[filter.accession_number.equals] => xxx
[filter.customfield-421250f4-ea28-42b2-b53d-06ba84f16d36.like] => xxx
)
and it leaves out the date, even though the print_r($data) is in the if statement for the date,
so the data += there is not adding that condition. There are other combinations where it does not update the $data array even though it satisfies the if condition. Just wondering if there is a better way to do that and why that is happening.
You're using the same key filter.customfield-421250f4-ea28-42b2-b53d-06ba84f16d36.like four times. Associative arrays must have unique keys. You can not do this:
$array = [
'foo' => 'bar1',
'foo' => 'bar2',
'foo' => 'bar3',
];
If you have this:
$array = [
'foo' => 'bar1',
];
And then try to merge an array containing an existing key,
$array += [
'foo' => 'bar2',
];
PHP will throw away the duplicate item(s) because the key(s) already exists.
If you instead do this:
$array = [
'foo' => 'bar1',
];
$array['foo'] = 'bar2';
Then PHP will overwrite the existing key with the new value, which isn't what you want either.
So, if you want to maintain all the values specified, you'll either need to use unique keys:
$array = [
'foo1' => 'bar1',
'foo2' => 'bar2',
'foo3' => 'bar3',
];
Or use an indexed array:
$array = [
'bar1',
'bar2',
'bar3',
];
Or maybe (fancy!) an indexed array inside an associative array:
$array = [
'foo' => [
'bar1',
'bar2',
'bar3',
],
];

Add and modify value in a deep nested mixed array

Let's say you have an array like this:
$list = array(
'name' => 'foobar',
'id' => '12302',
'group' => array(array(
'name' => 'teamA',
'members' => array(
array(
'ID' => 'OAHSJLASJ8888'
'name' => 'eric',
'fname' => 'lu',
'age' => '22'
),
array(
'ID' => 'OKZ8JJLJYYH6'
'name' => 'franz',
'fname' => 'as',
'age' => '33'
),
array(
'ID' => 'OKOIYHJKKK'
'name' => 'Amr',
'fname' => 'ok',
'age' => '13'
)
)
),
array(
'name' => 'teamB',
'members' => array(
array(
'ID' => 'FGZ9ILKA'
'name' => 'Evan',
'fname' => 'lu',
'age' => '22'
),
array(
'ID' => 'KMLML2039KKK'
'name' => 'Michel',
'fname' => 'as',
'age' => '33'
),
array(
'ID' => 'AAA2039KKK'
'name' => 'Nickr',
'fname' => 'ok',
'age' => '13'
)
)
)
)
);
You want to add a value to the associative array named Amr which is the third element of the member key of the group key $list[group][0][members][2][newKey] = B
Using recursive function and foreach, I'm able to find anything I'm aiming at. Using array_walk_recursive I can also find the targeted key value and modify it.
Using RecursiveIteratorIterator and foreach, I can also find the element and modify it's value.
My issue is that I can not replace the modified object within the tree. I can follow the path down, but I'm not able to climb the tree back. I could maintain a index of each array I traverse and then recalculate the path to the key, but it looks culprit to me.
I can not modify the data structure, the dataset I have is as is.
Thanks for any help you could bring.
Code for Iterator:
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($list));
foreach($iterator as $key=>$value) {
if ($key === 'ID') {
$metas = get_relatedmeta_objects($value),true));
//metas key should be added to the current array
}
}
Recursive method:
function searchKeyAndAdd( &$element) {
if(is_array($element) || is_object($element)){
foreach ( $element as &$key => $value ) {
if ($key === "ID") {
$metas = get_relatedmeta_objects($value);
//metas key should be added to the current array
} else if (is_array($value)) {
searchObject($value);
}
}
}
}
array_walk_recursive method:
function alterArray(&$item, $key, &$parentRec) {
if (is_array($item) || is_object($item)) {
searchObject($item);
}
if ($key === 'ID') {
$parentRec = json_decode(json_encode($parentRec), true);
$parentRec['metas'] = get_field_objects($item);
// the current array is modified but the value does not go back to the $list initial array.
}
}
function searchObject( &$element, &$parent) {
array_walk_recursive($element, 'alterArray', $element);
}
The data set could be anything. You do not know the key, you just know that some nested object can have ID key and when they do you want to add more content to this object.
The recursive function can do it, but you should use the & prefix on $value instead of $key:
function searchKeyAndAdd( &$element) {
if(is_array($element) || is_object($element)){
foreach ( $element as $key => &$value ) {
if ($key === "ID") {
$element['meta'] = get_relatedmeta_objects($value);
} else {
searchKeyAndAdd($value);
}
}
}
}
searchKeyAndAdd($list);
The other two methods offer no reference to the parent, although in the case of array_walk_recursive you tried it with the third argument, but there things get messy: to make it work on each recursive depth, you call array_walk_recursive recursively... but array_walk_recursive already visits all the key/value pairs recursively. So this will lead to many calls to alterArray with the same key/value, but with a different ancestor as third argument for each of them.
Furthermore, with this line:
$parentRec = json_decode(json_encode($parentRec), true);
... you lose the reference to the original $parentRec, and so any modification you make to $parentRec will no longer have an effect on the original array.

How to check if duplicate values of some indexes exist in multi dimensional array or not?

My problem is i have a multidimensional array posting from form to php, now i want to checking if duplicate values of some indexes exist in multi dimensional array or not?
e.g:
$data=Array
(
0 => Array
(
uid => '100',
name => 'Sandra Shush',
type => 'abc'
),
1 => Array
(
uid => '101',
name => 'Sandra Shushtext',
type => 'xyz'
),
2 => Array
(
uid => '100',
name => 'Sandra Shush',
type => 'abc'
)
);
here name and type of index 1 and 2 are same, so how can i check it?
I am familiar with
$key = array_search('abc', array_column($data, 'type'));
but it is for duplication of single column value in multi rows, in my situation if multi column of same rows same with multi column of any other row then record will be consider as duplicate.
Any help should be appreciated, Thanks in advance.
You can try using array_reduce by creating a key using your desired item keys:
$result = array_reduce($data, function ($carry, $item) {
$key = $item['uid'] . $item['type'];
$item['is_duplicate'] = isset($carry[$key]);
if ($item['is_duplicate']) {
$carry[] = $item;
} else {
$carry[$key] = $item;
}
return $carry;
}, []);
var_dump($result);
The easiest way, well at least the one I would use is to encode your arrays into md5 (or any other kind) string and compare those values. I think it is the most efficient in your case.
Example:
<?php
function arrayToString($array) {
$str = '';
if ( !is_array($array) )
return $str;
foreach ( $array as $key => $val ) {
$str .= $key . ':' . $val;
}
return $str;
}
$data=Array
(
0 => Array
(
'uid' => '100',
'name' => 'Sandra Shush',
'type' => 'abc'
),
1 => Array
(
'uid' => '100',
'name' => 'Sandra Shush',
'type' => 'xyz'
),
2 => Array
(
'uid' => '100',
'name' => 'Sandra Shush',
'type' => 'abc'
)
);
$temp = array();
foreach ( $data as $d ) {
array_push($temp, md5(arrayToString($d)));
}
$unique = array_unique($temp);
var_dump($unique); // prints unique array
This is a very fast designed approach and will find duplicates. Note that duplicates are elements which have the same value for the same key. So if any of uid, name or type match, they will be treated as duplicates. Therefore I adjust the third array element, because all elements in your array share the same values.
$data = [
....
2 =>
[
'uid' => '200',
'name' => 'Mandra Shush',
'type' => 'abcx'
]
];
$duplicates = [];
$valuesToCompare = ["uid", "name", "type"];
function equals($value, $toCompare, $keysToCompare)
{
foreach ($keysToCompare as $compareKey) {
if ($value[$compareKey] === $toCompare[$compareKey]) {
return true;
}
}
return false;
}
foreach ($data as $index => $element) {
foreach ($data as $indexInner => $elementToCompare) {
if ($index !== $indexInner) {
if (equals($element, $elementToCompare, $valuesToCompare)) {
$duplicates[] = [$index => $indexInner];
}
}
}
}
var_dump($duplicates);
This will output the following, which indicates we found 2 duplicates. Where element 0 is duplicate of 1, and 1 is duplicate of 0.
array (size=2)
0 =>
array (size=1)
0 => int 1
1 =>
array (size=1)
1 => int 0
I achieved above scenario like this:
Dont know which one is best mine or other's who posted answers.
foreach($data as $key => $row)
{
$combinedarr[] = array("name"=>$row["name"],"type"=>$row["type"]);
}
//chck if same facilitiy is being visit on same date twice
$countcomb = count($combinedarr);
$uniquearr = array_unique($combinedarr, SORT_REGULAR);
if($countcomb==count($uniquearr)){
}else{
//yes duplicate exists
};
Thanks again for those who answered.

How do I reform this array into a differently structured array

I have an array that looks like this:
[0] => Array
(
[name] => typeOfMusic
[value] => this_music_choice
)
[1] => Array
(
[name] => myMusicChoice
[value] => 9
)
[2] => Array
(
[name] => myMusicChoice
[value] => 8
)
I would like to reform this into something with roughly the following structure:
Array(
"typeOfMusic" => "this_music_choice",
"myMusicChoice" => array(9, 8)
)
I have written the following but it doesn't work:
foreach($originalArray as $key => $value) {
if( !empty($return[$value["name"]]) ){
$return[$value["name"]][] = $value["value"];
} else {
$return[$value["name"]] = $value["value"];
}
}
return $return;
I've tried lots of different combinations to try and get this working. My original array could contain several sets of keys that need converting to arrays (i.e. it's not always going to be just "myMusicChoice" that needs converting to an array) ?
I'm getting nowhere with this and would appreciate a little help. Many thanks.
You just need to loop over the data and create a new array with the name/value. If you see a repeat name, then change the value into an array.
Something like this:
$return = array();
foreach($originalArray as $data){
if(!isset($return[$data['name']])){
// This is the first time we've seen this name,
// it's not in $return, so let's add it
$return[$data['name']] = $data['value'];
}
elseif(!is_array($return[$data['name']])){
// We've seen this key before, but it's not already an array
// let's convert it to an array
$return[$data['name']] = array($return[$data['name']], $data['value']);
}
else{
// We've seen this key before, so let's just add to the array
$return[$data['name']][] = $data['value'];
}
}
DEMO: https://eval.in/173852
Here's a clean solution, which uses array_reduce
$a = [
[
'name' => 'typeOfMusic',
'value' => 'this_music_choice'
],
[
'name' => 'myMusicChoice',
'value' => 9
],
[
'name' => 'myMusicChoice',
'value' => 8
]
];
$r = array_reduce($a, function(&$array, $item){
// Has this key been initialized yet?
if (empty($array[$item['name']])) {
$array[$item['name']] = [];
}
$array[$item['name']][] = $item['value'];
return $array;
}, []);
$arr = array(
0 => array(
'name' => 'typeOfMusic',
'value' => 'this_music_choice'
),
1 => array(
'name' => 'myMusicChoice',
'value' => 9
),
2 => array(
'name' => 'myMusicChoice',
'value' => 8
)
);
$newArr = array();
$name = 'name';
$value = 'value';
$x = 0;
foreach($arr as $row) {
if ($x == 0) {
$newArr[$row[$$name]] = $row[$$value];
} else {
if (! is_array($newArr[$row[$$name]])) {
$newArr[$row[$$name]] = array();
}
array_push($newArr[$row[$$name]], $row[$$value]);
}
$x++;
}

Check if an array of an array contains a certain string

I'm checking to make sure an array of arrays does not contain certain strings before adding any new child arrays to the parent array
I want to make sure that if an array with the same website and condition exists a new child array will not be added to the parent array.
e.g. in this example the $newArr must not be inserted in to the array $arr because their already exists an array with the same website and condition.
$arr = array(
array(
'website' => 'amazon',
'price' => 20,
'location' => 'uk',
'link' => '...',
'condition' => 'new'
),
array(
'website' => 'abe',
'price' => 20,
'location' => 'uk',
'link' => '...',
'condition' => 'new'
)
);
$newArr = array(
'website' => 'amazon',
'price' => 60,
'location' => 'uk',
'link' => '...',
'condition' => 'new'
)
I'm looking for an easy solution as using the function in_array on the parent array is not enough.
code so far
$arr = array();
foreach($table->find('tr.result') as $row){
if(($website = $row->find('a img',0))
&& ($price = $row->find('span.results-price a',0))
&& ($location = $row->find('.results-explanatory-text-Logo'))
&& ($link = $row->find('a',0))){
$website = str_replace( array('.gif','.jpg','.png'), '', basename($website->src));
$price = floatval(trim(str_replace(',', '', $price->innertext), "£"));
$location = "uk";
$link = $link->href;
$arr[] = array(
'website' => $website,
'price' => $price,
'location' => $location,
'link' => $link,
'condition' => 'new'
);
}
}
You loop over $arr each time to look for $website and $condition (always 'new'?) or you can keep a secondary array of the found keys. If you're starting with an empty $arr each time, the second approach will work and be faster.
$arr = array();
$keys = array();
foreach($table->find('tr.result') as $row){
if(...){
...
$condition = 'new'; // set as needed
// track seen keys
$key = $website . '|' . $condition; // assumes neither field contains '|'
if (!isset($keys[$key])) {
$keys[$key] = true;
$arr[] = array(...);
}
}
}
I hope the comments in the below code speak for themselves... I'm not a PHP pro, and this is probably not the most elegant way, but I believe the logic makes sense. Obviously the $new_array object has some variables that aren't declared but it's for example only.
I hope that helps and that no one down votes me :)
<?php
// Original array
$arr = array();
foreach($result as $row) {
// Get the new array as an object first so we can check whether to add to the loop
$new_array = array(
'website' => $website,
'price' => $price,
'location' => $location,
'link' => $link,
'condition' => 'new'
);
// If the original array is empty there's no point in looping through it
if(!empty($arr)) {
foreach($arr as $child) {
// Check through each item of the original array
foreach($new_array as $compare) {
// Compare each item in the new array against the original array
if(in_array($compare, $child)) {
// if there's a match, the new array will not get added
continue;
}
}
}
}
// If there's no match, the new array gets added
$arr[] = $new_array;
}
?>

Categories