I was looking for some standard PHP function to replace some value of an array with other, but surprisingly I haven't found any, so I have to write my own:
function array_replace_value(&$ar, $value, $replacement)
{
if (($key = array_search($ar, $value)) !== FALSE) {
$ar[$key] = $replacement;
}
}
But I still wonder - for such an easy thing there must already be some function for it! Or maybe much easier solution than this one invented by me?
Note that this function will only do one replacement. I'm looking for existing solutions that similarly replace a single occurrence, as well as those that replace all occurrences.
Instead of a function that only replaces occurrences of one value in an array, there's the more general array_map:
array_map(function ($v) use ($value, $replacement) {
return $v == $value ? $replacement : $v;
}, $arr);
To replace multiple occurrences of multiple values using array of value => replacement:
array_map(function ($v) use ($replacement) {
return isset($replacement[$v]) ? $replacement[$v] : $v;
}, $arr);
To replace a single occurrence of one value, you'd use array_search as you do. Because the implementation is so short, there isn't much reason for the PHP developers to create a standard function to perform the task. Not to say that it doesn't make sense for you to create such a function, if you find yourself needing it often.
While there isn't one function equivalent to the sample code, you can use array_keys (with the optional search value parameter), array_fill and array_replace to achieve the same thing:
EDIT by Tomas: the code was not working, corrected it:
$ar = array_replace($ar,
array_fill_keys(
array_keys($ar, $value),
$replacement
)
);
If performance is an issue, one may consider not to create multiple functions within array_map(). Note that isset() is extremely fast, and this solutions does not call any other functions at all.
$replacements = array(
'search1' => 'replace1',
'search2' => 'replace2',
'search3' => 'replace3'
);
foreach ($a as $key => $value) {
if (isset($replacements[$value])) {
$a[$key] = $replacements[$value];
}
}
Try this function.
public function recursive_array_replace ($find, $replace, $array) {
if (!is_array($array)) {
return str_replace($find, $replace, $array);
}
$newArray = [];
foreach ($array as $key => $value) {
$newArray[$key] = recursive_array_replace($find, $replace, $value);
}
return $newArray;
}
Cheers!
$ar[array_search('green', $ar)] = 'value';
Depending whether it's the value, the key or both you want to find and replace on you could do something like this:
$array = json_decode( str_replace( $replace, $with, json_encode( $array ) ), true );
I'm not saying this is the most efficient or elegant, but nice and simple.
What about array_walk() with callback?
$array = ['*pasta', 'cola', 'pizza'];
$search = '*';
$replace = '\*';
array_walk($array,
function (&$v) use ($search, $replace){
$v = str_replace($search, $replace, $v);
}
);
print_r($array);
Based on Deept Raghav's answer, I created the follow solution that does regular expression search.
$arr = [
'Array Element 1',
'Array Element 2',
'Replace Me',
'Array Element 4',
];
$arr = array_replace(
$arr,
array_fill_keys(
array_keys(
preg_grep('/^Replace/', $arr)
),
'Array Element 3'
)
);
echo '<pre>', var_export($arr), '</pre>';
PhpFiddle: http://phpfiddle.org/lite/code/un7u-j1pt
PHP 8, a strict version to replace one string value with another:
array_map(fn (string $value): string => $value === $find ? $replace : $value, $array);
An example - replace value foo with bar:
array_map(fn (string $value): string => $value === 'foo' ? 'bar' : $value, $array);
You can make full string matches without specifying the keys of qualifying values, by calling preg_replace() with a pattern containing start and end of string anchors (^, $). If your search term may contain characters which have a special meaning to the regex engine, then be sure to escape them with preg_quote() to avoid breakage. While regex is not entirely called for, regex offers some very convenient ways to tweak the search term handling. (Demo)
function array_replace_value(&$ar, $value, $replacement)
{
$ar = preg_replace(
'/^' . preg_quote($value, '/') . '$/',
$replacement,
$ar
);
}
I might be more inclined to use array_map() with arrow function syntax so that global variables can be accessed within the custom function scope. (Demo)
$needle = 'foo';
$newValue = 'bar';
var_export(
array_map(fn($v) => $v === $needle ? $newValue : $v, $array)
);
$ar = array(1,2,3,4,5,6,7,8);
$find = array(2,3);
$replace = array(13);
function update_bundle_package($ar,$find,$replace){
foreach ($find as $x => $y) {
///TO REMOVE PACKAGE
if (($key = array_search($y, $ar)) !== false) {
unset($ar[$key]);
}
///TO REMOVE PACKAGE
}
$ar = array_merge($ar, $replace);
}
<b>$green_key = array_search('green', $input); // returns the first key whose value is 'green'
$input[$green_key] = 'apple'; // replace 'green' with 'apple'
Related
This question already has answers here:
Filter multidimensional array based on partial match of search value
(3 answers)
Closed 1 year ago.
$example = array('An example','Another example','Last example');
How can I do a loose search for the word "Last" in the above array?
echo array_search('Last example',$example);
The code above will only echo the value's key if the needle matches everything in the value exactly, which is what I don't want. I want something like this:
echo array_search('Last',$example);
And I want the value's key to echo if the value contains the word "Last".
To find values that match your search criteria, you can use array_filter function:
$example = array('An example','Another example','Last example');
$searchword = 'last';
$matches = array_filter($example, function($var) use ($searchword) { return preg_match("/\b$searchword\b/i", $var); });
Now $matches array will contain only elements from your original array that contain word last (case-insensitive).
If you need to find keys of the values that match the criteria, then you need to loop over the array:
$example = array('An example','Another example','One Example','Last example');
$searchword = 'last';
$matches = array();
foreach($example as $k=>$v) {
if(preg_match("/\b$searchword\b/i", $v)) {
$matches[$k] = $v;
}
}
Now array $matches contains key-value pairs from the original array where values contain (case- insensitive) word last.
function customSearch($keyword, $arrayToSearch){
foreach($arrayToSearch as $key => $arrayItem){
if( stristr( $arrayItem, $keyword ) ){
return $key;
}
}
}
$input= array('An example','Another example','Last example');
$needle = 'Last';
$ret = array_keys(array_filter($input, function($var) use ($needle){
return strpos($var, $needle) !== false;
}));
This will give you all the keys whose value contain the needle.
It finds an element's key with first match:
echo key(preg_grep('/\b$searchword\b/i', $example));
And if you need all keys use foreach:
foreach (preg_grep('/\b$searchword\b/i', $example) as $key => $value) {
echo $key;
}
The answer that Aleks G has given is not accurate enough.
$example = array('An example','Another example','One Example','Last example');
$searchword = 'last';
$matches = array();
foreach($example as $k=>$v) {
if(preg_match("/\b$searchword\b/i", $v)) {
$matches[$k] = $v;
}
}
The line
if(preg_match("/\b$searchword\b/i", $v)) {
should be replaced by these ones
$match_result = preg_match("/\b$searchword\b/i", $v);
if( $match_result!== false && $match_result === 1 ) {
Or more simply
if( preg_match("/\b$searchword\b/i", $v) === 1 ) {
In agreement with http://php.net/manual/en/function.preg-match.php
preg_match() returns 1 if the pattern matches given subject, 0 if it does not, or FALSE if an error occurred.
I do not like regex because as far as I know, they are always slower than a normal string function. So my solution is:
function substr_in_array($needle, array $haystack)
{
foreach($haystack as $value)
{
if(strpos($value, $needle) !== FALSE) return TRUE;
}
return FALSE;
}
I was also looking for a solution to OP's problem and I stumbled upon this question via Google. However, none of these answers did it for me so I came up with something a little different that works well.
$arr = array("YD-100 BLACK", "YD-100 GREEN", "YD-100 RED", "YJ-100 BLACK");
//split model number from color
$model = explode(" ",$arr[0])
//find all values that match the model number
$match_values = array_filter($arr, function($val,$key) use (&$model) { return stristr($val, $model[0]);}, ARRAY_FILTER_USE_BOTH);
//returns
//[0] => YD-100 BLACK
//[1] => YD-100 GREEN
//[2] => YD-100 RED
This will only work with PHP 5.6.0 and above.
Without foreach,
how can I turn an array like this
array("item1"=>"object1", "item2"=>"object2",......."item-n"=>"object-n");
to a string like this
item1='object1', item2='object2',.... item-n='object-n'
I thought about implode() already, but it doesn't implode the key with it.
If foreach it necessary, is it possible to not nest the foreach?
EDIT: I've changed the string
EDIT2/UPDATE:
This question was asked quite a while ago. At that time, I wanted to write everything in one line so I would use ternary operators and nest built in function calls in favor of foreach. That was not a good practice! Write code that is readable, whether it is concise or not doesn't matter that much.
In this case: putting the foreach in a function will be much more readable and modular than writing a one-liner(Even though all the answers are great!).
You could use http_build_query, like this:
<?php
$a=array("item1"=>"object1", "item2"=>"object2");
echo http_build_query($a,'',', ');
?>
Output:
item1=object1, item2=object2
Demo
and another way:
$input = array(
'item1' => 'object1',
'item2' => 'object2',
'item-n' => 'object-n'
);
$output = implode(', ', array_map(
function ($v, $k) {
if(is_array($v)){
return $k.'[]='.implode('&'.$k.'[]=', $v);
}else{
return $k.'='.$v;
}
},
$input,
array_keys($input)
));
or:
$output = implode(', ', array_map(
function ($v, $k) { return sprintf("%s='%s'", $k, $v); },
$input,
array_keys($input)
));
I spent measurements (100000 iterations), what fastest way to glue an associative array?
Objective: To obtain a line of 1,000 items, in this format: "key:value,key2:value2"
We have array (for example):
$array = [
'test0' => 344,
'test1' => 235,
'test2' => 876,
...
];
Test number one:
Use http_build_query and str_replace:
str_replace('=', ':', http_build_query($array, null, ','));
Average time to implode 1000 elements: 0.00012930955084904
Test number two:
Use array_map and implode:
implode(',', array_map(
function ($v, $k) {
return $k.':'.$v;
},
$array,
array_keys($array)
));
Average time to implode 1000 elements: 0.0004890081976675
Test number three:
Use array_walk and implode:
array_walk($array,
function (&$v, $k) {
$v = $k.':'.$v;
}
);
implode(',', $array);
Average time to implode 1000 elements: 0.0003874126245348
Test number four:
Use foreach:
$str = '';
foreach($array as $key=>$item) {
$str .= $key.':'.$item.',';
}
rtrim($str, ',');
Average time to implode 1000 elements: 0.00026632803902445
I can conclude that the best way to glue the array - use http_build_query and str_replace
I would use serialize() or json_encode().
While it won't give your the exact result string you want, it would be much easier to encode/store/retrieve/decode later on.
Using array_walk
$a = array("item1"=>"object1", "item2"=>"object2","item-n"=>"object-n");
$r=array();
array_walk($a, create_function('$b, $c', 'global $r; $r[]="$c=$b";'));
echo implode(', ', $r);
IDEONE
You could use PHP's array_reduce as well,
$a = ['Name' => 'Last Name'];
function acc($acc,$k)use($a){ return $acc .= $k.":".$a[$k].",";}
$imploded = array_reduce(array_keys($a), "acc");
Change
- return substr($result, (-1 * strlen($glue)));
+ return substr($result, 0, -1 * strlen($glue));
if you want to resive the entire String without the last $glue
function key_implode(&$array, $glue) {
$result = "";
foreach ($array as $key => $value) {
$result .= $key . "=" . $value . $glue;
}
return substr($result, (-1 * strlen($glue)));
}
And the usage:
$str = key_implode($yourArray, ",");
For debugging purposes. Recursive write an array of nested arrays to a string.
Used foreach. Function stores National Language characters.
function q($input)
{
$glue = ', ';
$function = function ($v, $k) use (&$function, $glue) {
if (is_array($v)) {
$arr = [];
foreach ($v as $key => $value) {
$arr[] = $function($value, $key);
}
$result = "{" . implode($glue, $arr) . "}";
} else {
$result = sprintf("%s=\"%s\"", $k, var_export($v, true));
}
return $result;
};
return implode($glue, array_map($function, $input, array_keys($input))) . "\n";
}
Here is a simple example, using class:
$input = array(
'element1' => 'value1',
'element2' => 'value2',
'element3' => 'value3'
);
echo FlatData::flatArray($input,', ', '=');
class FlatData
{
public static function flatArray(array $input = array(), $separator_elements = ', ', $separator = ': ')
{
$output = implode($separator_elements, array_map(
function ($v, $k, $s) {
return sprintf("%s{$s}%s", $k, $v);
},
$input,
array_keys($input),
array_fill(0, count($input), $separator)
));
return $output;
}
}
For create mysql where conditions from array
$sWheres = array('item1' => 'object1',
'item2' => 'object2',
'item3' => 1,
'item4' => array(4,5),
'item5' => array('object3','object4'));
$sWhere = '';
if(!empty($sWheres)){
$sWhereConditions = array();
foreach ($sWheres as $key => $value){
if(!empty($value)){
if(is_array($value)){
$value = array_filter($value); // For remove blank values from array
if(!empty($value)){
array_walk($value, function(&$item){ $item = sprintf("'%s'", $item); }); // For make value string type 'string'
$sWhereConditions[] = sprintf("%s in (%s)", $key, implode(', ', $value));
}
}else{
$sWhereConditions[] = sprintf("%s='%s'", $key, $value);
}
}
}
if(!empty($sWhereConditions)){
$sWhere .= "(".implode(' AND ', $sWhereConditions).")";
}
}
echo $sWhere; // (item1='object1' AND item2='object2' AND item3='1' AND item4 in ('4', '5') AND item5 in ('object3', 'object4'))
Short one:
$string = implode('; ', array_map(fn($k, $v) => "$k=$v", array_keys($array), $array));
Using explode to get an array from any string is always OK, because array is an always in standard structure.
But about array to string, is there any reason to use predefined string in codes? while the string SHOULD be in any format to use!
The good point of foreach is that you can create the string AS YOU NEED IT!
I'd suggest still using foreach quiet readable and clean.
$list = array('a'=>'1', 'b'=>'2', 'c'=>'3');
$sql_val = array();
foreach ($list as $key => $value) {
$sql_val[] = "(" . $key . ", '" . $value . "') ";
}
$sql_val = implode(', ', $sql_val);
with results:
(a, '1') , (b, '2') , (c, '3')
|
(a: '1') , (b: '2') , (c: '3')
|
a:'1' , b:'2' , c:'3'
etc.
Also if the question is outdated and the solution not requested anymore, I just found myself in the need of printing an array for debugging purposes (throwing an exception and showing the array that caused the problem).
For this reason, I anyway propose my simple solution (one line, like originally asked):
$array = ['a very' => ['complex' => 'array']];
$imploded = var_export($array, true);
This will return the exported var instead of directly printing it on the screen and the var $imploded will contain the full export.
I have been looking around for a while in the PHP manual and can't find any command that does what I want.
I have an array with Keys and Values, example:
$Fields = array("Color"=>"Bl","Taste"=>"Good","Height"=>"Tall");
Then I have a string, for example:
$Headline = "My black coffee is cold";
Now I want to find out if any of the array ($Fields) values match somewhere in the string ($Headline).
Example:
Array_function_xxx($Headline,$Fields);
Would give the result true because "bl" is in the string $Headline (as a part of "Black").
I'm asking because I need performance... If this isn't possible, I will just make my own function instead...
EDIT - I'm looking for something like stristr(string $haystack , array $needle);
Thanks
SOLUTION - I came up with his function.
function array_in_str($fString, $fArray) {
$rMatch = array();
foreach($fArray as $Value) {
$Pos = stripos($fString,$Value);
if($Pos !== false)
// Add whatever information you need
$rMatch[] = array( "Start"=>$Pos,
"End"=>$Pos+strlen($Value)-1,
"Value"=>$Value
);
}
return $rMatch;
}
The returning array now have information on where each matched word begins and ends.
This should help:
function Array_function_xxx($headline, $fields) {
$field_values = array_values($fields);
foreach ($field_values as $field_value) {
if (strpos($headline, $field_value) !== false) {
return true; // field value found in a string
}
}
return false; // nothing found during the loop
}
Replace name of the function with what you need.
EDIT:
Ok, alternative solution (probably giving better performance, allowing for case-insensitive search, but requiring proper values within $fields parameter) is:
function Array_function_xxx($headline, $fields) {
$regexp = '/(' . implode('|',array_values($fields)) . ')/i';
return (bool) preg_match($regexp, $headline);
}
http://www.php.net/manual/en/function.array-search.php
that's what you looking for
example from php.net
<?php
$array = array(0 => 'blue', 1 => 'red', 2 => 'green', 3 => 'red');
$key = array_search('green', $array); // $key = 2;
$key = array_search('red', $array); // $key = 1;
?>
How can I replace a sub string with some other string for all items of an array in PHP?
I don't want to use a loop to do it. Is there a predefined function in PHP that does exactly that?
How can I do that on keys of array?
Why not just use str_replace without a loop?
$array = array('foobar', 'foobaz');
$out = str_replace('foo', 'hello', $array);
$array = array_map(
function($str) {
return str_replace('foo', 'bar', $str);
},
$array
);
But array_map is just a hidden loop. Why not use a real one?
foreach ($array as &$str) {
$str = str_replace('foo', 'bar', $str);
}
That's much easier.
This is a very good idea that I found and used successfully:
function str_replace_json($search, $replace, $subject)
{
return json_decode(str_replace($search, $replace, json_encode($subject)), true);
}
It is good also for multidimensional arrays.
If you change the "true" to "false" then it will return an object instead of an associative array.
Source: Codelinks
I am not sure how efficient this is, but I wanted to replace strings in a big multidimensional array and did not want to loop through all items as the array structure is pretty dynamic.
I first json_encode the array into a string.
Replace all the strings I want (need to use preg_replace if there are non-English characters that get encoded by json_encode).
json_decode to get the array back.
function my_replace_array($array,$key,$val){
for($i=0;$i<count($array);$i++){
if(is_array($array[$i])){
$array[$i] = my_replace_array($array[$i],$key,$val);
}else{
$array[$i]=str_replace($key,$val,$array[$i]);
}
}
return $array;
}
With array_walk_recursive()
function replace_array_recursive( string $needle, string $replace, array &$haystack ){
array_walk_recursive($haystack,
function (&$item, $key, $data){
$item = str_replace( $data['needle'], $data['replace'], $item );
return $item;
},
[ 'needle' => $needle, 'replace' => $replace ]
);
}
$base = array('citrus' => array( "orange") , 'berries' => array("blackberry", "raspberry"), );
$replacements = array('citrus' => array('pineapple'), 'berries' => array('blueberry'));
$basket = array_replace_recursive($base, $replacements);
$basket = array_replace($base, $replacements);
Is there a better method than loop with strpos()?
Not i'm looking for partial matches and not an in_array() type method.
example needle and haystack and desired return:
$needles[0] = 'naan bread';
$needles[1] = 'cheesestrings';
$needles[2] = 'risotto';
$needles[3] = 'cake';
$haystack[0] = 'bread';
$haystack[1] = 'wine';
$haystack[2] = 'soup';
$haystack[3] = 'cheese';
//desired output - but what's the best method of getting this array?
$matches[0] = 'bread';
$matches[1] = 'cheese';
ie:
magic_function($haystack, %$needles%) !
foreach($haystack as $pattern) {
if (preg_grep('/'.$pattern.'/', $needles)) {
$matches[] = $pattern;
}
}
I think you are confusing $haystack and $needle in your question, because naan bread is not in haystack, nor is cheesestring. Your desired output suggests you are looking for cheese in cheesestring instead. For that, the following would work:
function in_array_multi($haystack, $needles)
{
$matches = array();
$haystack = implode('|', $haystack);
foreach($needles as $needle) {
if(strpos($haystack, $needle) !== FALSE) {
$matches[] = $needle;
}
}
return $matches;
}
For your given haystack and needles this performs twice as fast as a regex solution. Might change for different number of params though.
I think you'll have to roll your own. The User Contributed Comments to array_intersect() provide a number of alternative implementations (like this one). You would just have to replace the == matching against strstr().
$data[0] = 'naan bread';
$data[1] = 'cheesestrings';
$data[2] = 'risotto';
$data[3] = 'cake';
$search[0] = 'bread';
$search[1] = 'wine';
$search[2] = 'soup';
$search[3] = 'cheese';
preg_match_all(
'~' . implode('|', $search) . '~',
implode("\x00", $data),
$matches
);
print_r($matches[0]);
// [0] => bread
// [1] => cheese
You'll get better answers if you tell us more about the real problem.