See this:
$q = 'blah';
for($k = 0; $k < count($results_array); $k++){
$results_array_ . $k = explode(',', $results_array[$k]);
foreach($results_array_ . $k as $key => $value){
if (stripos($value, $q) === false) {
unset($results_array_ . $k[$key]);
break;
}
}
}
On line 3 I'm simply using "$results_array_ . $k" and it's working just fine, but on line 6 I'm getting PHP parse errors on "unset($results_array_ . $k[$key])", why is this happening?
I appreciate anykind of help
Why I'm doing it:
I have an array named results_array:
var_dump($results_array):
0 => php,mysql,jquery,ruby,html,css,lamp
1 => mouse,keyboard,laptop,pad
2 => table,sofa,caption
and I have a $q which stands for query, I want to search in the $results_array and remove the items which has nothing to do with the query, so if I set $q=a then results array should be this:
0 => lamp
1 => keyboard,laptop,pad
3 => table,sofa,caption
now, I want to put the above results in each index of the results_array, at the end results_array should be:
0 => lamp
1 => keyboard
2 => laptop
3 => pad
4 => table
5 => sofa
6 => caption
Answer to original question
unset expects its argument to be a direct reference to a value, e.g. $var or $array['key']. If you want to dynamically create the argument based on other values, you 'll have to use variable variable syntax:
unset(${$results_array_ . $k[$key]});
This will get rid of the warning, but it still won't make the code work because it's fundamentally flawed. Line 3 which you mention reads:
$results_array_ . $k = explode(',', $results_array[$k]);
What this does is explode an array into $k and then concatenate $results_array_ with $k and... throw away the result. You could just as easily have written
$k = explode(',', $results_array[$k]);
and it would work the same (except possibly not giving an E_NOTICE that $_results_array_ does not exist).
So, it seems that you have a misunderstanding of how some PHP fundamentals work. It would be best if you asked another question that explains what you are trying to do, in order to determine what would be a good way of doing it.
Answer to current question
Let's take the steps one at a time:
Take the array of strings and turn each string into an array with explode, making an array of arrays. You can do this with array_map or a simple foreach.
"Flatten" the array of arrays into one big array. You can do this with array_merge or array_merge_recursive (the details will be a bit different, the idea is the same).
Search the flattened array and filter out uninteresting elements with array_filter.
If necessary, reindex the filtered array so that it has consecutive numeric keys with array_values.
Here's code that does this, albeit a little differently (I am doing steps 1 and 2 at the same time in the first line using array_reduce):
$array = (...);
$array = array_reduce($array, function(&$result, $item) {
return array_merge($result, explode(',', $item));
}, array());
$array = array_filter($array, function($item) use ($string) {
return strpos($item, $string) !== false;
});
$result = array_values($array);
A version that does the same without using fancy functions:
// Step 1
foreach($array as &$row) {
$row = explode(',', $row);
}
unset($row);
// Step 2
$array = call_user_func_array('array_merge_recursive', $array);
// Step 3
foreach ($array as $k => $v) {
if(strpos($v, 'a') === false) unset($array[$k]);
}
// Step 4
$array = array_values($array);
Related
Hi i am stuck with a problem where in i have to find out the count of smaller no of element in an array i have implemented what we call as a brute force method but this isn't the optimised solution, can anyone help me out with the optimise solution for the code below
<?php
function find_small_count($arr){
$no_count = [];
foreach ($arr as $key => $value){
$no_count[$key] = 0;
foreach ($arr as $key1 => $value){
if ($arr[$key1] < $arr[$key]) {
$no_count[$key]++;
}
}
}
return $no_count;
}
print_r(find_small_count(['8','1','2','2','5']));
?>
Where in the expected Output should be [4,0,1,1,3]
I have three solutions for you. Let me explain
Working code sandbox
Solution 1
Use array_filter to return only qualified elements and then count the filtered array to get the count.
## Solution 1:
function find_small_count($arr)
{
$response = [];
foreach ($arr as $valueToSearch) {
$filtered = array_filter($arr, function ($value) use ($valueToSearch) {
return $value < $valueToSearch;
});
$response[] = ['valueToSearch' => $valueToSearch, 'count' => count($filtered)];
}
return $response;
}
print_r(find_small_count(['8', '1', '2', '2', '5']));
Solution 2
Sort the array in ascending order. When doing so your array has all numbers lesser than the current element appearing before it (in the array). Therefore the key for the array will be the count of all those numbers that are less than the current value, excluding the current number (keys start with 0).
Exception will be when a number appears twice, like 2 in your case. If we were to use key as the count in your case the first 2 will have count 1 and second 2 will have count 2, which is incorrect. Do note that the first 2 does give you the correct count.
To avoid this we can use array_unique and remove the duplicates. That will leave you with only one 2 in your response (the first one) and will give you the correct count.
You may think what about 5. For that we can fallback on the behavior of array_unique to preserve the keys. Hence even after array_unique 5 will retain its key, ie. 3. And our objective is accomplished. The only side effect is that the response will be [4,0,1,3] instead of [4,0,1,1,3]. So if that works you can use this method.
function find_small_count_two($arr){
$response = [];
sort($arr);
$arrUniqueAndSorted = array_unique($arr);
foreach ($arrUniqueAndSorted as $key => $value){
$response[] = ['valueToSearch' => $value, 'count' => $key];
}
return $response;
}
print_r(find_small_count_two(['8', '1', '2', '2', '5']));
Solution 3
Use array_search. From the docs
Searches the array for a given value and returns the first corresponding key if successful
Same logic as Solution 2 but this one avoids array_unique
function find_small_count_three($arr){
$response = [];
sort($arr);
foreach ($arr as $valueToCount){
$count =array_search($valueToCount, $arr);
$response[] = ['valueToSearch' => $valueToCount, 'count' => $count];
}
return $response;
}
I need to remove values from an array that occur more than one time in the array.
For example:
$value = array(10,10,5,8);
I need this result:
$value = array(5,8);
Is there any in-built function in php?
I tried this, but this will not return my expected result:
$unique = array_unique($value);
$dupes = array_diff_key($value, $unique);
You can use array functions and ditch the foreach loops if you wish:
Here is a one-liner:
Code:
$value = [10, 10, 5, 8];
var_export(array_keys(array_intersect(array_count_values($value),[1])));
As multi-line:
var_export(
array_keys(
array_intersect(
array_count_values($value),
[1]
)
)
);
Output:
array (
0 => 5,
1 => 8,
)
This gets the value counts as an array, then uses array_intersect() to only retain values that occur once, then turns the keys into the values of a zero-index array.
The above snippet works identically to #modsfabio's and #axiac's answers. The ONLY advantage in my snippet is brevity. It is possible that their solutions may outperform mine, but judging speed on relatively small data sets may be a waste of dev time. For anyone processing relatively large data sets, do your own benchmarking to find the technique that works best.
For lowest computational/time complexity, use a single loop and as you iterate conditionally populate a lookup array and unset() as needed.
Code: (Demo) (Crosslink to my CodeReview answer)
$values = [10, 10, 5, 8];
$found = [];
foreach ($values as $index => $value) {
if (!isset($found[$value])) {
$found[$value] = $index;
} else {
unset($values[$index], $values[$found[$value]]);
}
}
var_export($values);
// [2 => 5, 3 => 8]
A couple of notes:
If processing float values, using a technique that stores the values as keys (as all of my snippets do), then the results may be incorrect because php will change floats to integers when used as keys.
PHP is consistently much faster at searching for keys than it is at searching for values.
You can do it like this using array_count_values() and a foreach loop:
<?php
$input = array(10,10,5,8);
$output = array();
foreach(array_count_values($input) as $value => $count)
{
if($count == 1)
{
$output[] = $value;
}
}
var_dump($output);
Output:
array(2) {
[0]=>
int(5)
[1]=>
int(8)
}
Example: https://eval.in/819461
A possible approach:
$value = array(10,10,5,8);
$output = array_keys(
array_filter(
array_count_values($value),
function ($count) {
return $count == 1;
}
)
)
array_count_values() produces an array that associates to each unique value from $value the number of times it appears in the array.
array_filter() keeps in this result only the entries (the keys) that appear only once in the original array.
array_keys() produces the desired result.
I would use array_count_values to get an array with how often every element occurs in the array. Then remove all the elements from the original array that occur more than once.
You need to use array_count_values(), array_search() and unset() functions.
<?php
$value = array(10,10,5,8);
echo '<pre>';print_r($value);echo '</pre>';
$cnt = array_count_values($value);
$dup = array();
foreach ($cnt as $k => $repeated) {
if ($repeated > 1) {
if(($key = array_search($k, $value)) !== false) {
unset($value[$key]);
}
}
}
echo '<pre>';print_r($cnt);echo '</pre>';
echo '<pre>';print_r($value);echo '</pre>';
?>
Demo
you can use
foreach loop
and
array_diff() function:
$value=array(10,10,5,8);
$duplicated=array();
foreach($value as $k=>$v)
{
if($kt=array_search($v,$value))!==false and
$k!=$kt)
{if (count(array_keys($array, $value)) > 1)
{
/* Execute code */
}
unset($value[$kt];$duplicated[]=$v;
}
}
$result=array_diff($values,$duplicated);
print_r($result);
output
Array([2]=>5[3]=>8)
I have associative array such as:
$myArray = array(
'key1' => 'val 1',
'key2' => 'val 2'
...
);
I do not know the key values up front but want to start looping from the second element. In the example above, that would be from key2 onwards.
I tried
foreach(next(myArray) as $el) {
}
but that didnt work.
Alternatives may be array_slice but that seems messy. Am i missing something obvious?
There really is no "one true way" of doing this. So I'll take it as a benchmark as to where you should go.
All information is based on this array.
$array = array(
1 => 'First',
2 => 'Second',
3 => 'Third',
4 => 'Fourth',
5 => 'Fifth'
);
The array_slice() option. You said you thought this option was overkill, but it seems to me to be the shortest on code.
foreach (array_slice($array, 1) as $key => $val)
{
echo $key . ' ' . $val . PHP_EOL;
}
Doing this 1000 times takes 0.015888 seconds.
There is the array functions that handle the pointer, such as ...
current() - Return the current element in an array.
end() - Set the internal pointer of an array to its last element.
prev() - Rewind the internal array pointer.
reset() - Set the internal pointer of an array to its first element.
each() - Return the current key and value pair from an array and advance the array cursor.
Please note that the each() function has been deprecated as of PHP 7.2, and will be removed in PHP 8.
These functions give you the fastest solution possible, over 1000 iterations.
reset($array);
while (next($array) !== FALSE)
{
echo key($array) . ' ' . current($array) . PHP_EOL;
}
Doing this 1000 times, takes 0.014807 seconds.
Set a variable option.
$first = FALSE;
foreach ($array as $key => $val)
{
if ($first != TRUE)
{
$first = TRUE;
continue;
}
echo $key . ' ' . $val . PHP_EOL;
}
Doing this 1000 times takes 0.01635 seconds.
I rejected the array_shift options because it edits your array and you've never said that was acceptable.
This depends on whether you want to do this just once or many times, and on whether you still need the original array later on.
"First" pattern
$first = true;
foreach ($array as $key=>value) {
if($first) {
$first = false;
continue;
}
// ... more code ...
}
I personally use this solution quite often because it's really straight-forward, everybody gets this. Also, there is no performance hit of creating a new array and you can still operate on the original array after the loop.
However, if you have a couple of loops like this, it kind of starts looking a little unclean, because you need 5 extra lines of code per loop.
array_shift
array_shift($array);
foreach ($array as $key=>value) {
// .... more code ....
}
array_shift is a function tailored to this special case of not wanting the first element. Essentially it's a Perl-ish way of saying $array = array_slice($array, 1) which might not be completely obvious, especially since it modifies the original array.
So, you might want to make a copy of the original array and shift it, if you need both the shifted array multiple times and also the original array later on.
array_slice
And, of course, there is array_slice itself. I don't see anything wrong with array_slice if you want the original array to remain unchanged and you need the sliced array multiple times. However, if you're positive that you always want to slice just one element off, you might as well use the shorthand array_shift (and make a copy before if needed).
You can go with the obvious way:
$flag = false;
foreach($myArray as $el) {
if($flag) {
// do what you want
}
$flag = true;
}
Just another way of flexible iteration:
reset($myArray); // set array pointer to the first element
next($myArray); // skip first element
while (key($myArray) !== null) {
// do something with current($myArray)
next($myArray);
}
As far as I know foreach is just a kind of shortcut for this construction.
From Zend PHP 5 Certication study guide:
As you can see, using this set of functions [reset, next, key,
current, ...] requires quite a bit of work; to be fair, there are some
situations where they offer the only reasonable way of iterating
through an array, particularly if you need to skip back-and-forth
between its elements. If, however, all you need to do is iterate
through the entire array from start to finish, PHP provides a handy
shortcut in the form of the foreach() construct.
If your array was 0 based, it would be if($key>=1), but as your array starts at key 1, then this should work.
foreach ($array as $key=>$value){if($key>=2){
do stuff
}}
You could try:
$temp = array_shift($arr);
foreach($arr as $val) {
// do something
}
array_unshift($arr, $temp);
reset($myArray);
next($myArray);
while ($element = each($myArray))
{
//$element['key'] and $element['value'] can be used
}
My fairly simple solution when this issue pops up. It has the nice advantage of being easily being modified to be able to skip more than just the first element if you want it to.
$doomcounter = 0;
foreach ($doomsdayDevice as $timer){ if($doomcounter == 0){$doomcounter++; continue;}
// fun code goes here
}
I have an array ($arr):
[0] => Array
(
[sv_317] => 1,650
[sv_318] => 1,254
)
[1] => Array
(
[sv_317] => 1,580
[sv_318] => 1,580
)
I am trying to use these element values as number values and so need to remove any non numeric characters (commas in the above example).
To do this I am using:
foreach($arr as $k=>$v)
{
$v[sv_317] = str_replace(",", "", $v[sv_317]);
$v[sv_317] = preg_replace('/\s+/', '', $v[sv_317]);
$v[sv_318] = str_replace(",", "", $v[sv_318]);
$v[sv_318] = preg_replace('/\s+/', '', $v[sv_318]);
echo "318 :".$v[sv_318];
echo "317 :".$v[sv_317];
}
The echos are there just to test that it is doing what I intended, and sure enough they print the values of the elements without commas or white-space.
However this didn't result in being able to use the elements numerically, so I tested the array with print_r($arr); immediately following the above loop, and the array elements appeared unaffected (i.e. still containing commas.
Is there an issue of scope here? If so how can I remove the commas permanently?
Many thanks.
Since you're trying to change $v, it needs to be a reference variable, like this:
foreach($arr as $k => &$v) {
$v[sv_318] = str_replace(",", "", $v[sv_318]);
}
...But there is more to fix in your code:
You should unset($v) at the end, so subsequent code doesn't act strangely
The array indexes should be quoted, since they are string literals.
I prefer strtr() to str_replace(), since the correspondence is clearer:
.
foreach($arr as $k => &$v) {
$v['sv_318'] = strtr( $v['sv_318'], array(','=>'') );
}; unset($v);
Also, to handle any number of values in $v, I'd use another foreach:
foreach ($arr as $key => &$subarr) {
foreach ($subarr as $subkey => &$val) {
$val = strtr( $val, array(','=>'') );
}; unset($val);
}; unset($subarr);
The foreach loop doesn't work with the array itself. It works with a copy of the array. So, when you do print_r($arr) it's displaying the original array. The actual array $arr is not modified.
From PHP foreach documentation:
In order to be able to directly modify array elements within the loop precede $value with &. In that case the value will be assigned by reference.
<?php
$arr = array(1, 2, 3, 4);
foreach ($arr as &$value) {
$value = $value * 2;
}
// $arr is now array(2, 4, 6, 8)
unset($value); // break the reference with the last element
?>
Check this SO post to understand how foreach actually works:
How does PHP 'foreach' actually work?
Hope this answers your question :)
As a php beginner, I meet a problem with calculating the elements of array in php
$effect=array("a"=>array(1,2),"b"=>array(1,2),"c"=>array(1,2));
I just want to make the result as this
$effect['a'][0]=$effect['a'][0]/$effect['a'][1];
$effect['b'][0]=$effect['b'][0]/$effect['b'][1];
$effect['c'][0]=$effect['c'][0]/$effect['c'][1];
Except do this one by one , How to do this calculation with foreach or other loop way
Your array syntax is a bit off. It should be $effect['a'][0].
The loop is trivial, and foreach was the right idea.
You can use it to iterate over all the letters using:
foreach ($effect as $letter => $numbers) {
...
}
Then put your assignment/division line in the loop, replacing the fixed 'a' and 'b' etc. with the $letter variable.
You need something like this?
foreach ($effect as $key => $val)
{
$results[$key] = $val[0] / $val[1];
}
print_r($results);
Also one counter-intuitive thing in PHP, is that arrays are passed by value by default. You can use & to get a reference to the array
$effects =array("a"=>array(1,2),"b"=>array(1,2),"c"=>array(1,2));
foreach ( $effects as $key => &$effect ) {
$effect[0] = $effect[0]/$effect[1];
unset($effect);
}
print_r( $effects );