Nested foreach with arrays - php - php

The problem I am facing is when I use one foreach inside another and the array of the first foreach has more than 1 entries. What I want to do is to exclude all entries of array 1 from array 2. I've been on almost all related posts, cannot solve it by myself, I need a little help if possible. Sorry for my bad English.
Example:
$choice ---> array with random number of entries each time (for this example 2)
Example:
/var/www/clients/client1/web1/web/images,/var/www/clients/client1/web1/web/tmp
$list ---> array of random number of entries each time (for this example 10000)
Example:
/var/www/clients/client1/web1/web/images,/var/www/clients/client1/web1/web/tmp,/var/www/clients/client1/web1/web/includes,/var/www/clients/client1/web1/web/libraries,......
$list has always more entries than $choice
And I have this code here:
foreach ( $choice as $select )
{
foreach ( $list as $file )
{
if ( (strpos( $file, $select )) !== false )
{
// exclude this
}
else
{
// include this
}
}
}
What the above code will do (unfortunately) is:
Step 1. Will compare $select entry-1 with all $file entries.
Step 2. Will exclude $select entry-1 from all $file entries and will include the $select entry-2.
Step 3. Will compare $select entry-2 with all $file entries.
Step 4. Will exclude $select entry-2 from all $file entries and will include the $select entry-1.
Result:
Nothing excluded.
Any help truly appreciated. I am on this for like a week, all I have tried is putting them inside out I am out of ideas.
Thank you.

I believe you're trying to remove items that are in $list from $choice. (Or is it the other way around?) Have you tried the array_diff function? This will work if items in both array are equal. For example:
<?php
//Option 1: array_diff
$bigger = array("A", "B", "C", "D", "E", "F");
$smaller = array("A", "B");
$result = array_diff($bigger, $smaller);
print_r($result);
If you need to do additional processing on the removed items, you can try in_array, but this requires item equality (like above). For example:
//Option 2: in_array (only one foreach loop)
foreach ($smaller as $key => $item) {
if (in_array($item, $bigger)) {
//do something to "remove" it, for example:
unset($smaller[$key]);
unset($bigger[$key]);
//...
}
}
print_r($smaller);
print_r($bigger);
Lastly, if the items in both arrays are not guaranteed to be strictly equals, you could use a double foreach. You'll need to flag items in the inner loop and process them in the outer loop. For example:
//Option 3: double-foreach (items not strictly equals)
$choice = array(
"/var/www/clients/client1/web1/web/images",
"/var/www/clients/client1/web1/web/tmp"
);
$list = array(
"/var/www/clients/client1/web1/web/images",
"/var/www/clients/client1/web1/web/tmp",
"/var/www/clients/client1/web1/web/includes",
"/var/www/clients/client1/web1/web/libraries",
// more items
);
foreach ($choice as $choice_key => $choice_item) {
$exists_in_list = FALSE;
foreach ($list as $list_key => $list_item) {
if (strpos($list_item, $choice_item) !== FALSE) {
//$choice_item is string-contained inside $list_item:
$exists_in_list = TRUE;
//Do some processing on $list (while "$list_key" is in scope). For example:
unset($list[$list_key]); //removes the matching items from $list
//...
break;
}
}
if ($exists_in_list) {
//Do post-processing on $choice. For example:
unset($choice[$choice_key]); //removes the matching items from $choice
//...
}
}
echo '$choice is now ';
print_r($choice);
echo '$list is now ';
print_r($list);
The $result is:
//Option 1:
Array //$result == $bigger - $smaller
(
[2] => C
[3] => D
[4] => E
[5] => F
)
//Option 2:
Array //$smaller - $bigger
(
)
Array //$bigger - $smaller
(
[2] => C
[3] => D
[4] => E
[5] => F
)
//Option 3:
$choice is now Array
(
)
$list is now Array
(
[2] => /var/www/clients/client1/web1/web/includes
[3] => /var/www/clients/client1/web1/web/libraries
)

Related

Grouping multi-dimensional arrays in PHP

I can't focus right now and my mind keeps playing tricks on me with the solution to this.
I've tried a multitude of options but they keep not working.. Sigh.
Say I have a string as such; a.b.c|a.b.d|a.b.e|f|f.g|f.h|i, I want to create a new array (or object) as the following
A > B > C, D, E
F > G, H
I
With > being a nested array, , being an element in the parent array.
These should be able to continue nesting a multitude of times, e.g. A > B > C > D > E > F, D
Any guidance? I've tried exploding the string and then those strings to an array - this array holds A > B > C, A > B > D, A > B > E etc., I just can't get my head around to how to combine them efficiently.
I started with just looping over each element in the array and checking if the parents' key exists, but that was failing. Any help is appreciated as I'm incredibly tired, quite shocking I can do such a simple task.
<?php
// read line from standard input
$line = trim(fgets(STDIN));
echo "Line: $line\n"; // debug
// split lines by |
$segments = explode('|', $line);
print_r($segments); // debug
// prepare output array
$md_array = array();
// walk through the segments
foreach($segments as $segment) {
// set pointer to output array
$current = &$md_array;
// split segment by .
$tokens = explode('.', $segment);
print_r($tokens); // debug
foreach($tokens as $token) {
echo "working on $token\n";
// if key is not included in the array, create empty array
if( ! array_key_exists($token, $current) ) {
$current[$token] = array();
}
// pass the pointer to following sub-section
$current = &$current[$token];
}
}
// print out the output
print_r($md_array);
?>
Testing the script
echo "a.b.c|a.b.d|a.b.e|f|f.g|f.h|i" | php test.php
Output
Array
(
[a] => Array
(
[b] => Array
(
[c] => Array
(
)
[d] => Array
(
)
[e] => Array
(
)
)
)
[f] => Array
(
[g] => Array
(
)
[h] => Array
(
)
)
[i] => Array
(
)
)
Want to thank Richard for his solution, which allowed me to achieve my aim.
See the code below:
public static function permissions($permList) {
$segments = explode('|', $permList);
$md_array = array();
foreach($segments as $segment) {
$current = &$md_array;
$tokens = explode('.', $segment);
$x = 0;
foreach($tokens as $token) {
if(!array_key_exists($token, $current) ) {
if(count($tokens) > $x+1)
$current[$token] = array();
else
$current[] = $token;
}
if(count($tokens) > $x+1)
$current = &$current[$token];
$x++;
}
}
return $md_array;
}
If I input a.b.c|a.b.d|a.b.e|f|f.g|f.h|i, I am returned with the expected output above.
Many thanks.

PHP replace Array values based on certain requirements

I have an array as such:
$array = ["1","0","0","1","1"]
//replace with
$newArray = ["honda","toyota","mercedes","bmw","chevy"]
// only if the original array had a value of "1".
// for example this is my final desired output:
$newArray = ["honda","0","0","bmw","chevy"]
I want to change each value in a specific order IF and only if the array value is equal to "1".
For example the values, "honda", "toyota", "mercedes", "bmw", "chevy" should only replace the array values if the value is "1" otherwise do not replace it and they must be in the right position for example the first element in the array must only be changed to honda, not toyota or any of the other values.
I know I must iterate through the array and provide an if statement as such:
foreach($array as $val) {
if($val == 1){
//do something
} else {
return null;
}
}
Please guide me in the right direction and describe how to replace the values in order, so that toyota cannot replace the first array value only the second position.
You can so something like this - iterating over the array by reference and replacing when the value is 1 (string) and the value in the replace array exists:
foreach($array as $key => &$current) {
if($current === '1' && isset($replace[$key]))
$current = $replace[$key];
}
Output:
Array
(
[0] => honda
[1] => 0
[2] => 0
[3] => bmw
[4] => chevy
)
As per your comment, to output an imploded list of the cars that do have values, you can do something like this - filtering out all zero values and imploding with commas:
echo implode(
// delimiter
', ',
// callback - filter out anything that is "0"
array_filter($array, function($a) {
return $a != '0';
})
);
Currently, our if is asking if $val is true (or if it exists) while your numeric array's values are strings.
Try this:
$array = ["1","0","0","1","1"]
$newArray = ["honda","toyota","mercedes","bmw","chevy"]
foreach($array as $key => $val) {
if($val === '1'){ // if you only want honda
$array[$key] = $newArray[$key];
} else {
return null;
}
}
PHP Code
$array = array("1","0","0","1","1");
$newArray = array("honda","toyota","mercedes","bmw","chevy");
foreach($array as $key => $val) {
if($val === '1')
$array[$key] = $newArray[$key];
}
Would produce the answer you're looking for

Removing certain array element in a for-loop in PHP

I have inserted some elements (fruit names) queried from mySQL into an array. Now, I would like to remove certain items from the array. I want to remove 'Apple' and 'Orange' if the exist from the array. This is what I tried but I am getting an error message.
Array Example:
Array ( [1] => Orange [2] => Apple)
foreach($terms as $k => $v)
{
if (key($v) == "Apple")
{
unset($terms[$k]);
}
elseif( key($v) == "Orange")
{
unset($terms[$k]);
}
}
>>> Warning: key() expects parameter 1 to be array, string given //same error repeated 4 times
I referred to this link here: How do you remove an array element in a foreach loop?
I would be grateful if anyone can point out what I did wrong.
Have you tried it this way:
foreach($terms as $k => $v)
{
if ($v == "Apple")
{
unset($terms[$k]);
}
elseif($v == "Orange")
{
unset($terms[$k]);
}
}
Explanation:
The $fr is your actual array of all fruits.. and your $rm is another array that contains list of items to be removed from your $fr array.
Using a foreach cycle through the $rm array and see if the element exists on the $fr array , if found, unset() it.
The code...
<?php
$fr = array('Apple','Orange','Pineapple'); //<-- Your actual array
$rm = array('Apple','Orange'); //<--- Elements to be removed
foreach($rm as $v)
{
if(in_array($v,$fr))
{
unset($fr[array_search($v,$fr)]);
}
}
print_r($fr);
OUTPUT :
Array
(
[2] => Pineapple
)
Using array_diff()
print_r(array_diff($fr,$rm));
Code Demonstration

PHP - Use everything from 1st array, remove duplicates from 2nd?

I have 2 arrays - the first one is output first in full. The 2nd one may have some values that were already used/output with the first array. I want to "clean up" the 2nd array so that I can output its data without worrying about showing duplicates. Just to be sure I have the terminology right & don't have some sort of "array within an array", this is how I access each one:
1st Array
$firstResponse = $sth->fetchAll();
foreach ($firstResponse as $firstResponseItem) {
echo $firstResponseItem['samecolumnname']; // Don't care if it's in 2nd array
}
2nd Array
while( $secondResponseRow = $dbRequest->fetch_assoc() ){
$secondResponseArray = array($secondResponseRow);
foreach ($secondResponseArray as $secondResponseItem){
echo $secondResponseItem['samecolumnname']; //This can't match anything above
}
}
Thanks!
For example:
$response_names = array();
$firstResponse = $sth->fetchAll();
foreach ($firstResponse as $firstResponseItem)
$response_names[] = $firstResponseItem['samecolumnname'];
while( $secondResponseRow = $dbRequest->fetch_assoc() ){
$secondResponseArray = array($secondResponseRow);
foreach ($secondResponseArray as $secondResponseItem) {
if (!in_array($secondResponseItem['samecolumnname'], $response_names))
$response_names[] = $secondResponseItem['samecolumnname'];
}
}
array_walk($response_names, function($value) { echo $value . '<br />' });
If I understand what you're looking to do and the arrays are in the same scope, this should work.
$secondResponseArray = array($secondResponseRow);
$secondResponseArray = array_diff($secondResponseArray, $firstResponse);
//secondResponseArray now contains only unique items
foreach ($secondResponseArray as $secondResponseItem){
echo $secondResponseItem['samecolumnname'];
}
If you know that the keys of duplicate values will be the same you could use array_diff_assoc to get the items of the first array that aren't in the other supplied arrays.
This code
<?php
$a = array('abc', 'def', 'ghi', 'adg');
$b = array('abc', 'hfs', 'toast', 'adgi');
$r = array_diff_assoc($b, $a);
print_r($a);
print_r($r);
produces the following output
[kernel#~]php so_1.php
Array
(
[0] => abc
[1] => def
[2] => ghi
[3] => adg
)
Array
(
[1] => hfs
[2] => toast
[3] => adgi
)
[kernel#~]

How do I compare a huge amount of strings against the beginning of another?

I have two tables. One with a load of numbers. I then have another table with a list of prefixes( 30, 000+ ).
I need to loop through the prefixes and see if any of the numbers in table 1 starts with any of the prefixes.
This is what I have so far.
$tdata = $r->get_t_data(); //array of prefix
/*
Array
(
[0] => Array
(
[prefix] => 101
[dest] => UK
)
)
*/
$cdata = $r->get_c_data(); //array of number
/*Array
(
[0] => Array
(
[row] => 1
[num] => 441143610120
)
)*/
$temp = array();
$i=0;
$time=0;
foreach ($cdata as $ckey => $c) {
foreach ($tdata as $tkey => $t) {
$length = strlen($t['prefix']);
if (strpos($c['num'], $t['prefix'], 0, $length )) {
$temp[$i]['row']=$c['row'];
$temp[$i]['prefix']=$t['prefix'];
$temp[$i]['dialled']=$c['num'];
$temp[$i]['dest']=$t['dest'];
break;
$i++; //increment only if found
}
}
$time++;
}
so basically it loops through the numbers and then I try and match the first part of the number with the prefix.
At the moment it is returning and empty array.
Hope you can help
The best thing to do is to do the join in your sql as opposed to checking after in your PHP. To do a join with a like you can do this:
SELECT * FROM table t JOIN prefixTable p ON t.num LIKE CONCAT(p.prefix, '%')
The key is LIKE CONCAT(p.prefix, '%') that's saying combine the tables where t.num is like prefix%and in MySQL % is a wildcard since we didn't put a wild card at the front that means that the t.num column has to START with prefix
Your condition if (strpos($c['num'], $t['prefix'], 0, $length )) can return 0, which php will interpret as false. strpos should be checked like this:
if (false !== strpos($c['num'], $t['prefix'], 0, $length )) {}
use preg_grep to reduce the amount of looping/search code you have:
foreach ($table1 as $search) {
$safe_search = preg_quote($search);
$matches = preg_grep("/^$safe_search/", $prefix_array);
if (count($matches) > 0) {
echo "Found $search in the prefix array\n";
}
}

Categories