How to modify index keys using array_map() in PHP - php

I want to come up with $desired_output from given $data array below using array_map() or any PHP array_* built-in function. Any idea how?
$data = array(
'posted_name' => 'John Doe',
'posted_age' => '30',
);
$desired_output = array(
'name' => 'John Doe',
'age' => '30',
);
I tried below but the result is an array of arrays:
$desired_output = array_map(
function($keys, $vals)
{
$new[substr($keys, strlen('posted_'))] = $vals;
return $new;
},
array_keys($data),
$data
);
print_r($desired_output );
/**
* Array (
[0] => Array ( [name] => John Doe )
[1] => Array ( [age] => 30 )
)
*/

What about the following:
$desired_output = array();
array_walk(
$data,
function(&$val, $key) use (&$desired_output)
{
$len = strlen('posted_');
if (substr($key, 0, $len) == "posted_") {
$key = substr($key, $len);
}
$desired_output[$key] = $val;
}
);
print_r($desired_output);
Changes:
Using array_walk instead of array_map since _map cannot handle keys
Creating an empty array to build the result in
Using that array in the scope of the lambda function
Replacing the "posted_" only if it exists in the key
Output:
$ php -f ~/tmp/so2.php
Array
(
[name] => John Doe
[age] => 30
)

Related

codeigniter modify array from string for insert_batch

This is my form input $data, i want this keep this input.
$data = "39X3,29X5";
this my code convert string to array
$data = explode(",", $data);
$out = array();
$step = 0;
foreach($data as $key=>$item){
foreach(explode('X',$item) as $value){
$out[$key][$step++] = $value;
}
print '<pre>';
print_r($out);
print '</pre>';
result
Array
(
[0] => Array
(
[0] => 39
[1] => 3
)
[1] => Array
(
[2] => 29
[3] => 5
)
)
but i want change the keys and fix this for support query builder class
$this->db->insert_batch('mytable',$out).
Like this.
array
(
array
(
'number' => 39
'prize' => 3
),
array
(
'number' => 29
'prize' => 5
)
)
i try hard and confuse using loop.
So you need to remove inner foreach and put relevant values into array.
foreach($data as $key=>$item){
$exp = explode('X', $item);
$out[$key] = [
'number' => $exp[0],
'prize' => $exp[1]
];
}
Check result in demo
change your foreach loop to the following:
foreach($data as $key=>$item){
$temp = explode('X',$item);
$out[] = ['number' => $temp[0] , 'prize' => $temp[1]];
}

How to remove null values in multi-dimensional array?

I want to remove null values from this array.
Array(
[0] => Array( [fcmToken] => 123 )
[1] => Array( [fcmToken] => )
[2] => Array( [fcmToken] => 789 )
)
Expected Results
Array(
[0] => Array( [fcmToken] => 123 )
[1] => Array( [fcmToken] => 789 )
)
Here we are using foreach to iterate over values and using $value for non-empty $value["fcmToken"]
$result=array();
foreach($array as $key => $value)
{
if(!empty($value["fcmToken"]))
{
$result[]=$value;
}
}
print_r($result);
Output:
Array
(
[0] => Array
(
[fcmToken] => dfqVhqdqhpk
)
[1] => Array
(
[fcmToken] => dfgdfhqdqhpk
)
)
Use array_filter with a callback:
$r = array_filter($array, function($v) { return !empty($v['fcmToken']); });
For checking exactly null:
$r = array_filter($array, function($v) { return !is_null($v['fcmToken']); });
The best and easy single line solution for filter multidimensional array like below.
$aryMain = array_filter(array_map('array_filter', $aryMain));
I hope this solution is work for you. for more detail please visit below link.
PHP: remove empty array strings in multidimensional array
Danger! Do not trust empty() when dealing with numbers (or number-ish) values that could be zero!!! The same is true with using array_filter without a specific filtering parameter (as several answers on this page are using).
Look at how you can get the wrong output:
Bad Method:
$array = array(
array("fcmToken" => '0'),
array("fcmToken" => 123),
array("fcmToken" => ''),
array("fcmToken" => 789),
array("fcmToken" => 0)
);
$result=array(); // note, this line is unnecessary
foreach($array as $key => $value){ // note, $key is unnecessary
if(!empty($value["fcmToken"])){ // this is not a reliable method
$result[]=$value;
}
}
var_export($result);
Output:
array (
0 =>
array (
'fcmToken' => 123,
),
1 =>
array (
'fcmToken' => 789,
),
)
The zeros got swallowed up!
This is how it should be done:
Instead, you should use strlen() to check the values:
Method #1: foreach()
foreach($array as $sub){
if(strlen($sub["fcmToken"])){
$result[]=$sub;
}
}
var_export($result);
Method #2: array_filter() w/ anonymous function and array_values() for consistency
var_export(array_values(array_filter($array,function($a){return strlen($a['fcmToken']);})));
Output for either method:
array (
0 =>
array (
'fcmToken' => '0',
),
1 =>
array (
'fcmToken' => 123,
),
2 =>
array (
'fcmToken' => 789,
),
3 =>
array (
'fcmToken' => 0,
),
)
Demonstration of bad method and two good methods.
You need to do it using array_map, array_filter and array_values. Check below code :
$entry = array(
array("fcmToken" => 'dfqVhqdqhpk'),
array("fcmToken" => ''),
array("fcmToken" => 'dfgdfhqdqhpk'),
);
echo "<pre>";
$entry = array_values(array_filter(array_map('array_filter', $entry)));
print_r($entry);
Use this recursive function which iterates over any subarray and remove all elements with a null-value.
function removeNullValues ($array) {
foreach ($array as $key => $entry) {
if (is_array($entry)) {
$array[$key] = removeNullValues($entry);
if ($array[$key] === []) {
unset($array[$key]);
}
} else {
if ($entry === null) {
unset($array[$key]);
}
}
}
return $array;
}
Try using array_map() to apply the filter to every array in the array.

Array push multiple keys with array or string

I have the following array:
$array = array('23' => array('19' => array('7' => array('id' => 7, 'name' => 'John Doe'))));
Array
(
[23] => Array
(
[19] => Array
(
[7] => Array
(
[id] => 7
[name] => John Doe
)
)
)
)
I want to access sub-element and i know his sub keys that 23 19 7. I can do this with simple format
echo $array['23']['19']['7']['name']; // John Doe
But these array have just 3 level and this may vary, more or less. I have to make an array unlimited level.
I tried that like i want with following codes:
$keys = array('23', '19', '7');
echo $array[$keys]['name'];
And of course i got Warning: Illegal offset type in error.
Then i tried this one but i couldnt get any element:
function brackets($str) {
return sprintf("['%s']", $str);
}
$keys = array('23', '19', '7');
$string_key = implode('', array_map('brackets', $keys)); // ['23']['19']['7']
echo $array{$string_key}['name'];
You can make a function that you can call with a key-array.
function getArrayPathVal($arr, $path){
if(!is_array($path))
return $arr[$path];
$curr = $arr;
foreach($path as $key)
{
if(!$curr[$key])
return false;
$curr = $curr[$key];
}
return $curr;
}
$array = array('23' => array('19' => array('7' => array('id' => 7, 'name' => 'John Doe'))));
$keys = array('23', '19', '7');
$res = getArrayPathVal($array, $keys);
print $res['name']; //Prints 'John Doe'
You could try a recursive function:
function getByKeys ($arr, $keys) {
if (count($keys) == 0)
return $arr;
$key = array_shift ($keys);
return getByKeys ($arr[$key], $keys);
}
$array = array('23' => array('19' => array('7' => array('id' => 7, 'name' => 'John Doe'))));
echo getByKeys ($array, array('23', '19', '7'));
this is untested, but the concept should do the trick:
retrieve the next key to be applied to the array
next iteration using the sub-array denoted by that key
stop if no more keys should be applied.

remove duplicates from array (array unic by key) [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 3 months ago.
Array
(
[0] => Array
(
[file] => /var/websites/example.com/assets/images/200px/1419050406e6648e1c766551a0ffc91380fd6ff3406002011-10-233750.jpg
[md5] => 42479bee7a304d2318250de2ef1962a9
[url] => http://example.com/assets/images/200px/1419050406e6648e1c766551a0ffc91380fd6ff3406002011-10-233750.jpg
)
[1] => Array
(
[file] => /var/websites/example.com/assets/images/200px/21277792606e6648e1c766551a0ffc91380fd6ff3406002011-10-233750.jpg
[md5] => 42479bee7a304d2318250de2ef1962a9
[url] => http://example.com/assets/images/200px/21277792606e6648e1c766551a0ffc91380fd6ff3406002011-10-233750.jpg
)
)
How can I remove md5 key duplicates from above array?
<?php
$data = array(
array(
'md5' => 'alpha',
'some' => 'value',
),
array(
'md5' => 'alpha',
'some' => 'other value',
),
array(
'md5' => 'bravo',
'some' => 'third value',
),
);
// walk input array
$_data = array();
foreach ($data as $v) {
if (isset($_data[$v['md5']])) {
// found duplicate
continue;
}
// remember unique item
$_data[$v['md5']] = $v;
}
// if you need a zero-based array, otheriwse work with $_data
$data = array_values($_data);
PHP does already have a function to remove duplicate elements from an array. But unfortunately, array_unique does only support string based comparisons:
Note: Two elements are considered equal if and only if (string) $elem1 === (string) $elem2. In words: when the string representation is the same. The first element will be used.
The problem is that any array turned into a string is equal to any other array:
Arrays are always converted to the string "Array"; […]
But you can use the uniqueness of array keys to solve this:
$index = array();
foreach ($arr as $key => $item) {
if (isset($index[$item['md5']])) {
unset($item[$key]);
}
$index[$item['md5']] = TRUE;
}
Here is my final function after your help guys.... Hope it helps somebody in the future...
$data = array(
array(
'md5' => 'alpha',
'some' => 'value',
),
array(
'md5' => 'alpha',
'some' => 'other value',
),
array(
'md5' => 'bravo',
'some' => 'third value',
),
);
// walk input array
function remove_duplicateKeys($key,$data){
$_data = array();
foreach ($data as $v) {
if (isset($_data[$v[$key]])) {
// found duplicate
continue;
}
// remember unique item
$_data[$v[$key]] = $v;
}
// if you need a zero-based array
// otherwise work with $_data
$data = array_values($_data);
return $data;
}
$my_array = remove_duplicateKeys("md5",$data);
As array_unique operates on flat arrays, you can not use it directly. But you can first map all 'md5' values to a flat array, unique it and then get the elements with array_intersect_key:
$allMd5s = array_map(function($v) {return $v['md5'];}, $array);
$uniqueMd5s = array_unique($md5);
$result = array_intersect_key($arr, $uniqueMd5s);
Use array_filter(). Quick code test (doesn't necessarily mirror your situation, but you should get the idea):
<?php
header('Content-Type: Text/Plain');
$array = array(
0 => array('name' => 'samson'),
1 => array('name' => 'delilah'),
2 => array('name' => 'samson'),
3 => array('name' => 'goliath'),
);
$md5Processed = array();
$newArray = array_filter($array, "uniqueMD5");
print_r($newArray);
exit;
function uniqueMD5( $data ){
global $md5Processed;
if( !in_array( $data['name'], $md5Processed ) )
{
$md5Processed[] = $data['name'];
return true;
}
}
// your array
$array = array(...);
// will be used to store md5 hashes
$md5 = array();
// walk through array
foreach ($array as $key => $arr) {
// have we already seen this md5 hash?
if (in_array($arr['md5'], $md5)){
// remove element
unset($array[$key]);
}else {
// keep element, but add it's md5
$md5[] = $arr['md5'];
}
}
Tldr.: The obligatory one-liner:
$out = array_values ( array_intersect_key( $in, array_unique( array_column( $in, 'md5' ) ) ) );
And step by step (with my own example):
$in = [
[ 'k' => 'a' ],
[ 'k' => 'a' ],
[ 'k' => 'b' ]
];
print_r( array_column( $in, 'k' ) );
array_column returns a flat array, only with the values from all 'k'-keys:
Array
(
[0] => a
[1] => a
[2] => b
)
We can now filter that with array_unique:
print_r( array_unique( array_column( $in, 'k' ) ) ) );
To get:
Array
(
[0] => a
[2] => b
)
See that we kept the keys of the original array (0 and 2)?
We can use that with array_intersect_key. It computes the intersection of arrays using keys for comparison.
print_r( array_intersect_key( $in, array_unique( array_column( $in, 'k' ) ) ) );
We get the first [0] and third [2] entry of our original array.
Array
(
[0] => Array
(
[k] => a
)
[2] => Array
(
[k] => b
)
)
Now the keys are messed up (which might lead to problems if for loops), so we wrap the whole thing in array_values:
print_r(
array_values( array_intersect_key( $in, array_unique( array_column( $in, 'k' ) ) ) )
);
Array
(
[0] => Array
(
[k] => a
)
[1] => Array
(
[k] => b
)
)
Take a look at the function array_unique.

Sorting an array according to some duplicate values in PHP

I have an array containing strings of this format:
[0] => "title|url|score|user|date"
[1] => "title|url|score|user|date"
[2] => "title|url|score|user|date"
[3] => "title|url|score|user|date"
...
The score field is an int that is not always unique (for example, more than one entry can have a score of 0). I'm looking to sort the strings in this array based on their score value. Originally, I tried iterating through the array and making a new one with keys corresponding to the vote score. I soon realized that you can't have duplicate keys in an array.
Is there a good clean way of doing this?
$array = array(
0 => "title|url|12|user|date",
1 => "title|url|0|user|date",
2 => "title|url|13|user|date",
3 => "title|url|0|user|date"
);
function sortOnScore( $a, $b )
{
// discard first two values
list( ,,$scoreA ) = explode( '|', $a );
list( ,,$scoreB ) = explode( '|', $b );
return $scoreA == $scoreB ? 0 : ( $scoreA > $scoreB ? 1 : -1 );
}
usort( $array, 'sortOnScore' );
var_dump( $array );
Look into PHP's usort function
function score_sort($rec1, $rec2)
{
return $rec1['score'] - $rec2['score'];
}
usort($score_array);
Replace ['score'] with however you are extracting the scores from the strings
First you need to turn the strings into arrays with explode so you can do the comparisons:
// If using PHP >= 5.3, this can also be made into an anonymous function
function converter($string) {
$result = array_combine(
array('title', 'url', 'score', 'user', 'date'),
explode('|', $string)
);
// When these are later compared, it should be as numbers
$result['score'] = (int)$result['score'];
return $result;
}
$input = array(
'Foo|http://foo|0|user1|today',
// etc.
);
$converted = array_map('converter', $input);
This will make $converted look like:
array (
0 => array (
'title' => 'Foo',
'url' => 'http://foo',
'score' => '0',
'user' => 'user1',
'date' => 'today',
),
)
Then you can sort the array using the code from my answer here by easily specifying any sort criteria you want:
usort($converted, make_converter('score', 'date', 'title'));
Personally I'd be tempted to iterate through the array, split it by the |'s and put it into a new multi-dimensional array, for example something like this:
[0] => array([title]=>'title',[url]=>'url',[score]=>'score',[user]=>'user',[date]=>'date')
[1] => array([title]=>'title',[url]=>'url',[score]=>'score',[user]=>'user',[date]=>'date')
Then it becomes easy to sort, just use a function like this:
function sortmulti ($array, $index, $order, $natsort=FALSE, $case_sensitive=FALSE) {
if(is_array($array) && count($array)>0) {
foreach(array_keys($array) as $key) {
$temp[$key]=$array[$key][$index];
}
if(!$natsort) {
if ($order=='asc') {
asort($temp);
} else {
arsort($temp);
}
}
else
{
if ($case_sensitive===true) {
natsort($temp);
} else {
natcasesort($temp);
}
if($order!='asc') {
$temp=array_reverse($temp,TRUE);
}
}
foreach(array_keys($temp) as $key) {
if (is_numeric($key)) {
$sorted[]=$array[$key];
} else {
$sorted[$key]=$array[$key];
}
}
return $sorted;
}
return $sorted;
}
i.e. do this:
$sortedarray = sortmulti($array,'score','asc');
It would be very easy using the asort function:
$pattern = '#^([^|]+)\|([^|]+)\|([^|]+)\|([^|]+)\|([^|]+)$#';
$sorted = array();
foreach($data as $s) $sorted[] = preg_replace($pattern, '$3|$1|$2|$4|$5', $s);
asort($sorted);
these 4 lines of code, when given $data:
Array
(
[0] => title_0|url_0|6|user_0|date_0
[1] => title_1|url_1|6|user_1|date_1
[2] => title_2|url_2|2|user_2|date_2
[3] => title_3|url_3|3|user_3|date_3
[4] => title_4|url_4|2|user_4|date_4
[5] => title_5|url_5|7|user_5|date_5
[6] => title_6|url_6|3|user_6|date_6
[7] => title_7|url_7|8|user_7|date_7
[8] => title_8|url_8|3|user_8|date_8
[9] => title_9|url_9|9|user_9|date_9
)
will generate $sorted:
Array
(
[2] => 2|title_2|url_2|user_2|date_2
[4] => 2|title_4|url_4|user_4|date_4
[3] => 3|title_3|url_3|user_3|date_3
[6] => 3|title_6|url_6|user_6|date_6
[8] => 3|title_8|url_8|user_8|date_8
[0] => 6|title_0|url_0|user_0|date_0
[1] => 6|title_1|url_1|user_1|date_1
[5] => 7|title_5|url_5|user_5|date_5
[7] => 8|title_7|url_7|user_7|date_7
[9] => 9|title_9|url_9|user_9|date_9
)
and with just 2 more lines you can have the items in each element of the array back in the original order/format:
$data = array();
foreach($sorted as $s) $data[] = preg_replace($pattern, '$2|$3|$1|$4|$5', $s);
setting $data to:
Array
(
[0] => title_2|url_2|2|user_2|date_2
[1] => title_4|url_4|2|user_4|date_4
[2] => title_3|url_3|3|user_3|date_3
[3] => title_6|url_6|3|user_6|date_6
[4] => title_8|url_8|3|user_8|date_8
[5] => title_0|url_0|6|user_0|date_0
[6] => title_1|url_1|6|user_1|date_1
[7] => title_5|url_5|7|user_5|date_5
[8] => title_7|url_7|8|user_7|date_7
[9] => title_9|url_9|9|user_9|date_9
)
Create a new array of arrays:
[0] => array("score", old_array[0])
Then sort.

Categories