PHP How to merge two arrays inside a loop - php

I have a problem with the code below which is driving me crazy. What I want to do is to compare a given array with a sentence and then I need to know their position in the sentence for each occurrence, by now the script only return just one array, for example with the positions in which the name Marta is found inside the sentence. I trying to merge all the results in just one array but I'm a bit lost at the moment. I hope someone can give me some clues to make it. Best regards.
$sentence = 'Maria is Maria and Marta is Marta.';
$womennames = array("Maria","Marta");
function poswomen($chain, $words){
foreach($words as $findme){
$valida_existe = substr_count($chain,$findme);
$largo_encuentra = strlen($findme);
$posicion = array();
for($x=0; $x < strlen($chain); $x++){
$posic_x = strpos($chain, $findme, $x);
if($posic_x >= 0){
$posicion[] = $posic_x;
$x = $x+$largo_encuentra;
}
}
$posicion = array_unique($posicion);
$posicion = implode(",",$posicion);
}
return $posicion;
}
poswomen($sentence, $womennames);
print_r (poswomen($sentence, $womennames));

Just like barmar has said, your position keeps resetting you need to set it outside, from that , then add the currently found position so that it will carry on. Consider this example:
$sentence = 'Maria is Maria and Marta is Marta.';
$women_names = array('Maria', 'Marta');
$pos = 0;
$positions = array();
foreach($women_names as $name) {
while (($pos = strpos($sentence, $name, $pos))!== false) {
$positions[$name][] = $pos;
$pos += strlen($name);
}
$positions[$name] = implode(', ', $positions[$name]);
}
echo '<pre>';
print_r($positions);
echo '</pre>';
Sample Output:
Array
(
[Maria] => 0, 9
[Marta] => 19, 28
)

Related

Mix array with ancestor elements

Seems to be very simple but I'm like, losing a lot of time on this... and no success...
If I have a string:
$str = "She sells seashells"
So I turn every word into an array element
$array = explode(" ", $str);
What I need is, every word receive the ancestor element (if any) and the next ones...
Example result in json format (more easy to show)
"{"She":["sells","seashells"],"sells":["She","seashells"],"seashells":["She","sells"]}"
Can somebody help?
Thanks!
Really, you can copy a source array for each key, excluding that key:
$str = "She sells seashells";
$array = explode(" ", $str);
$res = [];
for($i = 0; $i < count($array); $i++) {
$res[$array[$i]] = $array;
unset($res[$array[$i]][$i]);
}
print_r($res);
demo
<?php
$str = "She sells seashells";
$arr = explode(" ",$str);
$length = count($arr);
$result = [];
for($i = 0;$i < $length;++$i){
$result[$arr[$i]] = [];
foreach ($arr as $each_val) {
if($each_val === $arr[$i]) continue;
$result[$arr[$i]][] = $each_val;
}
}
echo json_encode($result);
OUTPUT:
{"She":["sells","seashells"],"sells":["She","seashells"],"seashells":["She","sells"]}
Explode the string based on spaces.
Have a result array and make the current iteration value in for loop as the key for it.
Loop again over the array and check if current value matches with outer for loop value. If yes, then continue, else add that value in this result array key.
In the end, json_encode() it and you are done.

Trying to manipulate an array with PHP

I did not want to ask, but I am still quite new to PHP and I am stuck.
I have a comma separated list stored in MySQL; Blue, 12, Red, 15 etc.
I can bring it out and do most of what I want, but I am confused on how to proceed.
Ultimately, I would like to change the output of the data from
Blue, 12, Red, 15,
to
Blue => 12, Red => 15 (without the last comma) So I can use the data in a program I am attempting to build.
Currently, I am able to achieve:
Blue, => 12, => Red, => 15,
Code:
$result = $con->query($sql);
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
$id = $row['id'];
$type = $row["dataname"];
$datas = $type;
eval( "\$test = array (" . $datas . ");") ;
foreach($test as $test)
{
echo "<option name='$test'>$test , =></option>";
}
}
}
Using the desired output, I will be able to input data from a form to create an SVGGraph.
Thank you in advance for any assistance.
Ok so first off, I would try storing this information in separate rows in the future, comma separated lists are for when we do not have databases (simple text files for example).
But to answer your question (assuming result is the string of separated values):
$result = explode(',', $result);
$output = [];
for($i = 0;$i < count($result);$i=$i+2){
array_push($output, $result[i] => $result[i+1]);
}
//output:
$str = ""
foreach($output as $key => $value){
str .= $key . ' => ' . $value . ' ,';
}
$str = rtrim($str, ',');
echo $str //this will be your output
using eval is just the worst.
Here is how I would do it while keeping to your code as much as possible:
$result = $con->query($sql);
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
$id = $row['id'];
$type = $row["dataname"];
$datas = $type;
$res = array();
$arr = explode(",", str_replace(" ","",$datas));
for ($i = 0; $i < count($arr); $i+=2) {
$res[$arr[$i]] = $arr[$i + 1];
}
foreach($res as $key=>$value)
{
echo "<option name='$value'>$key , =></option>";
}
}
}
First of all, try not to use eval - it is dangerous.:)
Second, try to get all the data you need into one big string. Then you can use the explode PHP function to convert the string into individual elements. And the last thing you would do is to simply iterate over the array and assign the first item as a key and the second item as an element into yet another array.
I will leave the actual implementation to you as an excercise in your PHP coding skills.:)
//trim comma from the right
$str = rtrim('Blue, 12, Red, 15,', ',');
//create a helper array
$array = explode(', ', $str);
//arrange elements in the new array
for ($i = 0; $i < count($array) - 1; $i = $i + 2) {
$new[] = $array[$i] . ' => ' . $array[$i + 1];
}
//output new elements
echo implode(', ', $new);
Please dont use eval. You nearly always can avoid it and is dangerous.
Here is a solution which works without eval:
$result = $con->query($sql);
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
$id = $row['id'];
$type = $row["dataname"]; // Thats our comma-seperated list, right?
$arr = explode(',', $type); // Make $type to array
array_pop($arr); // Delete last element because its empty
// We go through the array with step = 2
// because the first is always the key and the second the value
for($i = 0; $i < count($arr); $i += 2)
{
echo "<option name='$arr[$i+1]'>$arr[$i] , =></option>";
}
}
}
Why eval is evil:
Whatever is in the string is evaled as code from your script with all rights the script has incuding file-access and so on. Since the string for your eval comes from the database you cant even be absolutely sure that it is no bad code you are executing when using eval.
Furthermore eval is bad when it comes to debugging things.
And at the end: Why producing overhead with stuff you can avoid?
It is in general recognized as bad style when using eval because of all this reasons. Better you never get used to it
If I understand correctly, you go from a string to an array to a string.
If so, it is possible to skip the array by using regex. Depending on the length of your string, creating a huge array may be a problem.
So I came up with those examples:
$input = "Blue, 1, Red, 2, Green, 3, Violet, 4,";
// Output: Blue => 1, Red => 2, Green => 3, Violet => 4
echo rtrim(preg_replace('/(([^,]*),([^,]*)),+/', '\2 =>\3,', $input), ',');
// Output <option name="Blue">Blue => 1</option><option name="Red">Red => 2</option><option name="Green">Green => 3</option><option name="Violet">Violet => 4</option>
echo preg_replace('/(\s*([^,]*)\s*,\s*([^,]*)\s*),+/', '<option name="\2">\2 => \3</option>', $input);
As you can see, no looping involved.
I hope it helped
EDIT
Here is links to visualize the regex
First regex
Second regex

checking if an array has values also in another array

I have an array which is structured like this:
funActivities(array)
0(array)
Activity(array)
id 4
name walks
1(array)
Activity(array)
id 5
name cycling
2(array)
Activity(array)
id 6
name sand pit
and then another like:
activities
0(array)
id 4
name walks
1(array)
id 6
name sand pit
I want to compare the two arrays and end up with an array which only contains the activities from the 1st array which don't appear in the 2nd array. So in this case I'd end up with just cycling in the array. It's in the first array, but not the second.
Whats the best way to do that?
i made a php function that works for you...
i hope this can help. of course there are some things i could do better but for this szenario it works
<?php
$funActivities[0]['Activity']['id'] = 4;
$funActivities[0]['Activity']['name'] = "walks";
$funActivities[1]['Activity']['id'] = 5;
$funActivities[1]['Activity']['name'] = "cycling";
$funActivities[2]['Activity']['id'] = 6;
$funActivities[2]['Activity']['name'] = "sand pit";
$activities[0]['id'] = 4;
$activities[0]['name'] = "walks";
$activities[1]['id'] = 6;
$activities[1]['name'] = "sand pit";
function compareArray($needle,$haystack)
{
$tmpArray = $haystack;
foreach($needle as $n)
{
$s1 = $n['id'].$n['name'];
$count = 0;
foreach($haystack as $h)
{
$s2 = $h['Activity']['id'].$h['Activity']['name'];
if( $s1 == $s2)
{
unset($tmpArray[$count]);
}
$count++;
}
}
return array_values($tmpArray);
}
$arr = compareArray($activities,$funActivities);
echo "<pre>";
print_r($arr);
echo "</pre>";
?>

how to order in while loop?

I want to get the count of characters from the following words in the string. For example, if my input is I am John then the output must be like this:
9 // count of 'I am John'
4 // count of 'I am'
1 // count of 'I'
I use the code like this in PHP for this process:
$string = 'I am John';
$words = explode(' ',$string);
$count_words = count($words);
$i =0;
while ($i<$count_words){
if($i==0) {
$words_length[$i] = strlen($words[$i]);
} else {
$words_length[$i] = strlen($words[$i])+1+$words_length[$i-1];
}
echo $words_length[$i]."<br>";
$i++;
}
But it return the output like this:
1
4
9
Why ? Where is my error ? How can I change the ordering ? What does my code must be like ?
Thanks in advance!
If you simply want to have the output in reverse order use array_reverse:
print_r(array_reverse($words_length));
Your problem is that you're looping through the words left to right. You can't output the full length right to left, because each one depends on the words to it's left.
You could take the echo out of the loop, and print the values after all have been calculated.
$string = 'I am John';
$words = explode(' ',$string);
$count_words = count($words);
$i =0;
while ($i<$count_words){
if($i==0) {
$words_length[$i] = strlen($words[$i]);
} else {
$words_length[$i] = strlen($words[$i])+1+$words_length[$i-1];
}
$i++;
}
print implode('<br />', array_reverse($words_length));
The quickest fix is to add print_r(array_reverse($words_length)); after the loop
You may use foreach and array_reverse to get the array values:
foreach(array_reverse($words_length) as $val){
echo $val;
}

"Unfolding" a String

I have a set of strings, each string has a variable number of segments separated by pipes (|), e.g.:
$string = 'abc|b|ac';
Each segment with more than one char should be expanded into all the possible one char combinations, for 3 segments the following "algorithm" works wonderfully:
$result = array();
$string = explode('|', 'abc|b|ac');
foreach (str_split($string[0]) as $i)
{
foreach (str_split($string[1]) as $j)
{
foreach (str_split($string[2]) as $k)
{
$result[] = implode('|', array($i, $j, $k)); // more...
}
}
}
print_r($result);
Output:
$result = array('a|b|a', 'a|b|c', 'b|b|a', 'b|b|c', 'c|b|a', 'c|b|c');
Obviously, for more than 3 segments the code starts to get extremely messy, since I need to add (and check) more and more inner loops. I tried coming up with a dynamic solution but I can't figure out how to generate the correct combination for all the segments (individually and as a whole). I also looked at some combinatorics source code but I'm unable to combine the different combinations of my segments.
I appreciate if anyone can point me in the right direction.
Recursion to the rescue (you might need to tweak a bit to cover edge cases, but it works):
function explodinator($str) {
$segments = explode('|', $str);
$pieces = array_map('str_split', $segments);
return e_helper($pieces);
}
function e_helper($pieces) {
if (count($pieces) == 1)
return $pieces[0];
$first = array_shift($pieces);
$subs = e_helper($pieces);
foreach($first as $char) {
foreach ($subs as $sub) {
$result[] = $char . '|' . $sub;
}
}
return $result;
}
print_r(explodinator('abc|b|ac'));
Outputs:
Array
(
[0] => a|b|a
[1] => a|b|c
[2] => b|b|a
[3] => b|b|c
[4] => c|b|a
[5] => c|b|c
)
As seen on ideone.
This looks like a job for recursive programming! :P
I first looked at this and thought it was going to be a on-liner (and probably is in perl).
There are other non-recursive ways (enumerate all combinations of indexes into segments then loop through, for example) but I think this is more interesting, and probably 'better'.
$str = explode('|', 'abc|b|ac');
$strlen = count( $str );
$results = array();
function splitAndForeach( $bchar , $oldindex, $tempthread) {
global $strlen, $str, $results;
$temp = $tempthread;
$newindex = $oldindex + 1;
if ( $bchar != '') { array_push($temp, $bchar ); }
if ( $newindex <= $strlen ){
print "starting foreach loop on string '".$str[$newindex-1]."' \n";
foreach(str_split( $str[$newindex - 1] ) as $c) {
print "Going into next depth ($newindex) of recursion on char $c \n";
splitAndForeach( $c , $newindex, $temp);
}
} else {
$found = implode('|', $temp);
print "Array length (max recursion depth) reached, result: $found \n";
array_push( $results, $found );
$temp = $tempthread;
$index = 0;
print "***************** Reset index to 0 *****************\n\n";
}
}
splitAndForeach('', 0, array() );
print "your results: \n";
print_r($results);
You could have two arrays: the alternatives and a current counter.
$alternatives = array(array('a', 'b', 'c'), array('b'), array('a', 'c'));
$counter = array(0, 0, 0);
Then, in a loop, you increment the "last digit" of the counter, and if that is equal to the number of alternatives for that position, you reset that "digit" to zero and increment the "digit" left to it. This works just like counting with decimal numbers.
The string for each step is built by concatenating the $alternatives[$i][$counter[$i]] for each digit.
You are finished when the "first digit" becomes as large as the number of alternatives for that digit.
Example: for the above variables, the counter would get the following values in the steps:
0,0,0
0,0,1
1,0,0 (overflow in the last two digit)
1,0,1
2,0,0 (overflow in the last two digits)
2,0,1
3,0,0 (finished, since the first "digit" has only 3 alternatives)

Categories