Related
Is it possible to search an array for a given value and return all the indexes at which the value was found? So for this array:
["Red","Green","Red","Blue"]
I need
[0,2]
with regard to a search for "Red". Searching for "Yellow" in this case would return an empty array.
You can use like this:
$array = ["Red","Green","Red","Blue"];
$output = array_keys($array, "Red");
The $output will be [0,2]
I think this should work:
$input = ["Red","Green","Red","Blue"];
$x = "Red";
$keys = array_keys(array_filter($input, function ($v) use ($x) { return $v === $x;}));
You can iterate the array with foreach:
foreach($input_arr as $key => $value){
if($value == 'Red'){
needed_key_arr[] = $key;
}
}
Also, if you can have an array of values you what to search use:
$lookup_arr = ['Red', 'Green'];
foreach($input_arr as $key => $value){
if(in_array($value, $lookup_arr)){
needed_key_arr[] = $key;
}
}
$arr = ["Red","Green","Red","Blue"];
$valueToSearchFor = ["Red"];
$keys = array_keys(array_filter($arr, function ($val1) use ($valueToSearchFor) { // filter the first array
return array_filter($valueToSearchFor, function ($val) use ($val1) { // use the first array's value
return $val == $val1; // compare them and then return them
});
}));
var_dump($keys) // array(2) { [0]=> int(0) [1]=> int(2) }
First we filter the array then take the values from the first filter to another filter then we match the arrays and we return them. This works for multiple values too.
$arr = ["Red","Green","Red","Blue"];
$valueToSearchFor = ["Red", "Blue"];
$keys = array_keys(array_filter($arr, function ($val1) use ($valueToSearchFor) {
return array_filter($valueToSearchFor, function ($val) use ($val1) {
return $val == $val1;
});
}));
var_dump($keys) // array(3) { [0]=> int(0) [1]=> int(2) [2]=> int(3) }
There are two arrays:
$arr1 = ['word', 'tech', 'care', 'kek', 'lol', 'wild', 'regex'];
$arr2 = ['ord', 'ek', 'ol', 'ld', 'gex', 'ss'];
The number of elements in the second array is less than or equal to the first array.
Sort out the first array and the second array, if the elements of the second array are contained at the end of the elements of the first array, sort the array in this form:
Array
(
[0] => w_ord
[1] => tech
[2] => care
[3] => k_ek
[4] => l_ol
[5] => wi_ld
[6] => re_gex
)
Important: the elements of the second array are never repeated, and can go in any order. If in the second element there is no end of the element of the first array, then set the value of the element of the first array.
I do this:
foreach($arr2 as $val) {
$strrepl[$val] = "_".$val;
}
foreach($arr1 as $key => $val) {
$arr3[$key] = str_replace(array_keys($strrepl), $strrepl, $val);
}
print_r($arr3);
But I'm not sure that this is the right approach, what will you advise?
Hmm, let's see ... purely functional 'cause you know :D
function ends($str) {
return function($suffix) use($str) {
return mb_strlen($str) >= mb_strlen($suffix)
&& mb_substr($str, mb_strlen($suffix) * -1) === $suffix;
};
}
$result = array_map(function($item) use($arr2) {
$filter = ends($item);
$suffixes = array_filter($arr2, $filter);
if (empty($suffixes)) {
return $item;
}
// This only cares about the very first match, but
// is easily adaptable to handle all of them
$suffix = reset($suffixes);
return mb_substr($item, 0, mb_strlen($suffix) * -1) . "_{$suffix}";
}, $arr1);
Surprisingly, this one was quite fun to execute.
Since you went very specific on end of the element, I decided to use RegEx for that.
Here is my approach:
$arr1 = ['word', 'tech', 'care', 'kek', 'lol', 'wild', 'regex'];
$arr2 = ['ord', 'ek', 'ol', 'ld', 'gex', 'ss'];
foreach ($arr2 as $find) {
foreach ($arr1 as $key => $element) {
$arr1[$key] = preg_replace('/' . $find . '$/', '_' . $find, $element);
}
}
For every element of the second array (since they are not repeated), I go through every element of the first array and check if the value can be found at the end of the element of the second array using the $ anchor from RegEx which forces it to look it from the end of the string.
This way the $arr1 will have exactly what you expect.
[Edit]
Following the scape suggestion from #aefxx and improving variable names.
You can use preg_grep which is regex on arrays.
This code will also make sure it can output more than one matching word from $arr1.
$arr1 = ['word', 'chord', 'tech', 'care', 'kek', 'lol', 'wild', 'regex'];
$arr2 = ['ord', 'ek', 'ol', 'ld', 'gex', 'ss'];
$keys=[];
foreach($arr2 as $val){
$matches = preg_grep("/.+" . preg_quote($val) . "/", $arr1);
$keys = array_merge($keys, array_keys($matches)); // save keys of matched words
foreach($matches as $key => $m) $new[$val][] = str_replace($val, "_$val", $arr1[$key]);
}
$new['unmatched'] = array_diff_key($arr1, array_flip($keys)); // add unmatched words
var_dump($new);
Output:
array(6) {
["ord"]=>
array(2) {
[0]=>
string(5) "w_ord"
[1]=>
string(6) "ch_ord"
}
["ek"]=>
array(1) {
[0]=>
string(4) "k_ek"
}
["ol"]=>
array(1) {
[0]=>
string(4) "l_ol"
}
["ld"]=>
array(1) {
[0]=>
string(5) "wi_ld"
}
["gex"]=>
array(1) {
[0]=>
string(6) "re_gex"
}
["unmatched"]=>
array(2) {
[2]=>
string(4) "tech"
[3]=>
string(4) "care"
}
}
https://3v4l.org/gfUea
You can try this.I think it is easy to understand :
$arr1=['word','tech','care','kek','lol','wild','regex'];
$arr2=['ord','ek','ol','ld','gex','ss'];
foreach($arr1 as $key=>$fullword){
foreach($arr2 as $substr){
$arr1[$key]=preg_replace('/' . $substr . '$/', '_' . $substr, $fullword,-1,$count);
if($count) break;
}
}
i go throught the array of fullword and as soon as i find a match i stop the search.
Another approach can be to create complex regex beforehand (using implode and preg_quote for safety) and use it for replacement inside array_map callback:
$arr1 = ['word', 'tech', 'care', 'kek', 'lol', 'wild', 'regex'];
$arr2 = ['ord', 'ek', 'ol', 'ld', 'gex', 'ss'];
$regex = '/(' . implode('|', array_map('preg_quote', $arr2)) . ')$/';
$result = array_map(function ($word) use ($regex) {
return preg_replace($regex, '_$1', $word);
}, $arr1);
Here is the demo.
I have an array in PHP and I don't know how to delete all the elements from every array element from certain character on, icluding that character. Is there a way to do this?
array(1092) {
["Piper;Rosii;Sare;Test;Vinete#####Piper ->Negru;Rosii ->Călite;Sare ->De masă, grunjoasă;Vinete ->Prăjite"]=>
int(124)
}
In my example I want to delete all text from "#####", including "#####" to the end, foreach array element. Is this possible? Or is there a PHP function for this?
UPDATE
My result should look like this:
array(1092) {
["Piper;Rosii;Sare;Test;Vinete]=>
int(124)
}
You can use array_walk to apply the substr and strpos to each element:
$array = [
'23845637;54634;345;3453345;#####morestuff',
'234234#####34596078345j34534534',
'34343245dfg#####asdfsadf;23452345;sdfsdf;345345'
];
array_walk($array, function(&$value, $key) {
$value = substr($value, 0, strpos($value, '#####'));
});
var_dump($array);
Will result in:
array(3) {
[0]=>
string(27) "23845637;54634;345;3453345;"
[1]=>
string(6) "234234"
[2]=>
string(11) "34343245dfg"
}
This will modify the original array.
For each element in the array, we search for the position of '#####' in the string and only take the part from 0 to the position in the string where '#####' occurs.
This will do that by looping through the array exploding the key by ##### and adding it to a new array. I did it in a loop in case your array is bigger than 1
<?php
$oldArray = array("Piper;Rosii;Sare;Test;Vinete#####Piper ->Negru;Rosii ->Călite;Sare ->De masă, grunjoasă;Vinete ->Prăjite" => 124);
$newArray = array();
foreach ($oldArray as $key => $row) {
$newKey = explode('#####', $key);
$newArray[$newKey[0]] = $row;
}
var_dump($newArray);
You can use substr and strpos to add the new entry and then unset the old entry in the array like this example:
$array = array(
"Piper;Rosii;Sare;Test;Vinete#####Piper ->Negru;Rosii ->Călite;Sare ->De masă, grunjoasă;Vinete ->Prăjite" => 124
);
foreach ($array as $key => $value) {
$array[substr($key, 0, strpos($key, '#####'))] = $value;
unset($array[$key]);
}
var_dump($array);
Will result in:
array(1) {
["Piper;Rosii;Sare;Test;Vinete"]=>
int(124)
}
Remove element from array if string contains any of the characters.For example Below is the actual array.
array(1390) {
[0]=>
string(9) "Rs.52.68""
[1]=>
string(20) ""php code generator""
[2]=>
string(9) ""Rs.1.29""
[3]=>
string(21) ""php codes for login""
[4]=>
string(10) ""Rs.70.23""
}
I need the array to remove all the elements which start with RS.
Expected Result
array(1390) {
[0]=>
string(20) ""php code generator""
[1]=>
string(21) ""php codes for login""
}
What i tried so far :
foreach($arr as $ll)
{
if (strpos($ll,'RS.') !== false) {
echo 'unwanted element';
}
From above code how can i remove unwanted elements from array .
You can get the $key in the foreach loop and use unset() on your array:
foreach ($arr as $key => $ll) {
if (strpos($ll,'RS.') !== false) {
unset($arr[$key]);
}
}
Note that this would remove none of your items as "RS" never appears. Only "Rs".
This sounds like a job for array_filter. It allows you to specify a callback function that can do any test you like. If the callback returns true, the value if returned in the resulting array. If it returns false, then the value is filtered out.
$arr = array_filter($arr,
function($item) {
return strpos($item, 'Rs.') === false;
});
Rs is different than RS you want to use stripos rather than strpos for non case sensitive checking
foreach($arr as $key => $ll)
{
if (stripos($ll,'RS.') !== false) {
unset($arr[$key]);
}
}
or use arrayfilter as pointed out
PHP's explode function returns an array of strings split on some provided substring. It will return empty strings when there are leading, trailing, or consecutive delimiters, like this:
var_dump(explode('/', '1/2//3/'));
array(5) {
[0]=>
string(1) "1"
[1]=>
string(1) "2"
[2]=>
string(0) ""
[3]=>
string(1) "3"
[4]=>
string(0) ""
}
Is there some different function or option or anything that would return everything except the empty strings?
var_dump(different_explode('/', '1/2//3/'));
array(3) {
[0]=>
string(1) "1"
[1]=>
string(1) "2"
[2]=>
string(1) "3"
}
Try preg_split.
$exploded = preg_split('#/#', '1/2//3/', -1, PREG_SPLIT_NO_EMPTY);
array_filter will remove the blank fields, here is an example without the filter:
print_r(explode('/', '1/2//3/'))
prints:
Array
(
[0] => 1
[1] => 2
[2] =>
[3] => 3
[4] =>
)
With the filter:
php> print_r(array_filter(explode('/', '1/2//3/')))
Prints:
Array
(
[0] => 1
[1] => 2
[3] => 3
)
You'll get all values that resolve to "false" filtered out.
see http://uk.php.net/manual/en/function.array-filter.php
Just for variety:
array_diff(explode('/', '1/2//3/'), array(''))
This also works, but does mess up the array indexes unlike preg_split. Some people might like it better than having to declare a callback function to use array_filter.
function not_empty_string($s) {
return $s !== "";
}
array_filter(explode('/', '1/2//3/'), 'not_empty_string');
I have used this in TYPO3, look at the $onlyNonEmptyValues parameter:
function trimExplode($delim, $string, $onlyNonEmptyValues=0){
$temp = explode($delim,$string);
$newtemp=array();
while(list($key,$val)=each($temp)) {
if (!$onlyNonEmptyValues || strcmp("",trim($val))) {
$newtemp[]=trim($val);
}
}
reset($newtemp);
return $newtemp;
}
It doesn't mess up the indexes:
var_dump(trimExplode('/', '1/2//3/',1));
Result:
array(3) {
[0]=>
string(1) "1"
[1]=>
string(1) "2"
[2]=>
string(1) "3"
}
Here is a solution that should output a newly indexed array.
$result = array_deflate( explode( $delim, $array) );
function array_deflate( $arr, $emptyval='' ){
$ret=[];
for($i=0,$L=count($arr); $i<$L; ++$i)
if($arr[$i] !== $emptyval) $ret[]=$arr[$i];
return $ret;
}
While fairly similar to some other suggestion, this implementation has the benefit of generic use. For arrays with non-string elements, provide a typed empty value as the second argument.
array_deflate( $objArray, new stdClass() );
array_deflate( $databaseArray, NULL );
array_deflate( $intArray, NULL );
array_deflate( $arrayArray, [] );
array_deflate( $assocArrayArray, [''=>NULL] );
array_deflate( $processedArray, new Exception('processing error') );
.
.
.
With an optional filter argument..
function array_deflate( $arr, $trigger='', $filter=NULL, $compare=NULL){
$ret=[];
if ($filter === NULL) $filter = function($el) { return $el; };
if ($compare === NULL) $compare = function($a,$b) { return $a===$b; };
for($i=0,$L=count($arr); $i<$L; ++$i)
if( !$compare(arr[$i],$trigger) ) $ret[]=$arr[$i];
else $filter($arr[$i]);
return $ret;
}
With usage..
function targetHandler($t){ /* .... */ }
array_deflate( $haystack, $needle, targetHandler );
Turning array_deflate into a way of processing choice elements and removing them from your array. Also nicer is to turn the if statement into a comparison function that is also passed as an argument in case you get fancy.
array_inflate being the reverse, would take an extra array as the first parameter which matches are pushed to while non-matches are filtered.
function array_inflate($dest,$src,$trigger='', $filter=NULL, $compare=NULL){
if ($filter === NULL) $filter = function($el) { return $el; };
if ($compare === NULL) $compare = function($a,$b) { return $a===$b; };
for($i=0,$L=count($src); $i<$L; ++$i)
if( $compare(src[$i],$trigger) ) $dest[]=$src[$i];
else $filter($src[$i]);
return $dest;
}
With usage..
$smartppl=[];
$smartppl=array_inflate( $smartppl,
$allppl,
(object)['intelligence'=>110],
cureStupid,
isSmart);
function isSmart($a,$threshold){
if( isset($a->intellgence) ) //has intelligence?
if( isset($threshold->intellgence) ) //has intelligence?
if( $a->intelligence >= $threshold->intelligence )
return true;
else return INVALID_THRESHOLD; //error
else return INVALID_TARGET; //error
return false;
}
function cureStupid($person){
$dangerous_chemical = selectNeurosteroid();
applyNeurosteroid($person, $dangerous_chemical);
if( isSmart($person,(object)['intelligence'=>110]) )
return $person;
else
lobotomize($person);
return $person;
}
Thus providing an ideal algorithm for the world's educational problems. Aaand I'll stop there before I tweak this into something else..
Write a wrapper function to strip them
function MyExplode($sep, $str)
{
$arr = explode($sep, $str);
foreach($arr as $item)
if(item != "")
$out[] = $item;
return $out;
}
Use this function to filter the output of the explode function
function filter_empty(&$arrayvar) {
$newarray = array();
foreach ($arrayvar as $k => $value)
if ($value !== "")
$newarray[$k] = $value;
$arrayvar = $newarray;
}
Regular expression solutions tend to be much slower than basic text replacement, so i'd replace double seperators with single seperators, trim the string of any whitespace and then use explode:
// assuming $source = '1/2//3/';
$source = str_replace('//', '/', $source);
$source = trim($source);
$parts = explode('/', $source);
No regex overhead - should be reasonably efficient, strlen just counts the bytes
Drop the array_values() if you don't care about indexes
Make it into function explode_interesting( $array, $fix_index = 0 ) if you want
$interesting = array_values(
array_filter(
explode('/', '/1//2//3///4/0/false' ),
function ($val) { return strlen($val); }
));
echo "<pre>", var_export( $interesting, true ), "</pre>";
enjoy, Jeff
PHP's split function is similar to the explode function, except that it allows you to enter a regex pattern as the delimiter. Something to the effect of:
$exploded_arr = split('/\/+/', '1/2//3/');
I usually wrap it in a call to array_filter, e.g.
var_dump(array_filter(explode('/', '1/2//3/'))
=>
array(3) {
[0]=>
string(1) "1"
[1]=>
string(1) "2"
[3]=>
string(1) "3"
}
Be aware, of course, that array keys are maintained; if you don't want this behaviour, remember to add an outer wrapper call to array_values().