All Combinations of one Array with 2 connectors - php

My problem is relatively simple but I cannot figure it out a reasonable algorithm by myself
I have an array which can be any length (n>=2), and I want to connect the elements with 2 separators ( '_' and '+' ):
So for example when my array has 2 elements [0,1] the result would be
[0_1, 0+1]
For 3 elements [0,1,2]
0_1_2,
0+1+2,
0+1_2,
0_1+2,
0_2+1
For 4 elements [0,1,2,3]
0_1_2_3,
0+1+2+3,
0+1_2_3,
0_1+2_3,
0_1_2+3,
0_2+1+3,
0_2+1_3,
0_3+1+2,
0_3+1_2
For 5 elements [0,1,2,3,4]
0_1_2_3_4,
0+1_2_3_4,
0_1+2_3_4,
0_1_2+3_4,
0_1_2_3+4,
0+1+2+3+4,
0_2+1+3+4,
0_2+1_3_4,
0_2+1+3_4,
0_2+1_3+4,
...
I hope this explanation is somewhat clear.

Not sure if this hits spec, but its a start:
$new = [];
$arr = [1,2,3,4,5];
for($i=0;$i<count($arr);$i++) {
$new[] = implode("_",$arr);
$arr[] = array_shift($arr);
}
foreach($new as $n) {
$o = $n;
while(strpos($o,"_")) {
$o = preg_replace("/_/","+",$o,1);
$new[] = $o;
}
$o = strrev($n);
while(strpos($o,"_")) {
$o = preg_replace("/_/","+",$o,1);
$new[] = $o;
}
}
print_r($new);

Related

Optimize multidimensional array creation

I have a list of array keys and nesting level in one array, for example:
$keys[0] = 'first';
$keys[1] = 'second';
$keys[2] = 'third';
How can I transform this into a multidimensional array in the following format:
$array['first']['second']['third'] = 'value';
I tried a couple different variations that did not work out and the keys overwrote themselves. The simplest way is to get a count of the number of keys and manually cover each scenario but this is hardly optimized and does not dynamically grow.
$keyLen = count($keys);
if ($keyLen == 1) {
$array[$keys[0]] = 'value;
} elseif ($keyLen == 2) {
$array[$keys[0]][$keys[1]] = 'value;
} elseif ($keyLen == 3) {
$array[$keys[0]][$keys[1]][$keys[2]] = 'value';
} ...
A couple notes, the value is not of significance it's the nesting of the array keys, and I cannot change the initial array format.
You could go backwards through your input array and wrap the previous result as you go:
$nested = 'value';
for (end($keys); key($keys)!==null; prev($keys)){
$nested = [current($keys) => $nested];
}
At the end $nested will have the desired structure.
Give this a try. Here we're using references to stack our new arrays.
<?php
$keys = array('first', 'second', 'third');
$array = array();
$current = &$array;
foreach($keys as $key => $value) {
$current[$value] = array();
$current = &$current[$value];
}
$current = 'Hello world!';
print_r($array);
Starting from the last Item you can loop through the array, pop the last one and build the new array:
<?php
$keys[0] = 'first';
$keys[1] = 'second';
$keys[2] = 'third';
function createKey($array) {
$b = "value";
while(count($array)>0) {
$key = array_pop($array);
$b = [$key => $b];
}
return $b;
}
var_dump(createKey($keys));
// Output:
array(1) {
["first"]=>
array(1) {
["second"]=>
array(1) {
["third"]=>
string(5) "value"
}
}
}
Another option is to loop the reversed keys and wrap the previous result:
$array = [];
foreach(array_reverse($keys) as $key) {
$temp = $array;
unset($array[key($array)]);
$array[$key] = $temp;
}
Then you could set your value:
$array['first']['second']['third'] = 'value';
Demo
You could even eval this in a safe way without leaking any input data into the eval-string:
$value = 'value';
eval( '$array[$keys['. implode(']][$keys[', range(0, count($keys)-1)) . ']] = $value;' );
or with an additional counter even simpler and shorter:
$value = 'value';
$i = 0;
eval( '$array' . str_repeat('[$keys[$i++]]', count($keys)) . ' = $value;' );

Getting Undefined:Offset error messages with Sorting Algorithm

So I'm getting a lot of these errors when I run this code. I'm about to give up and just use the sorting functions baked into PHP. But I would love if anyone could see the problem here. Please see below code. Sorry in advance if it's hard to read.
The array input is fine as print_r outputs exactly as expected, but the actual sorting algorithm just won't work, no matter what I try. The two commented functions at the bottom were used in different trials.
<?php
//this function will pull a string from a txt file and pass characters to an array
function strToArray($file){
if ($handle = fopen($file, 'r')){
$string = fread($handle, filesize($file));
fclose($handle);
}
$strArray = str_split(preg_replace('/\s+/', '', $string)); //regex in preg_replace gets rid of all whitespaces; str_split converts string to array
$arrLen = array_count_values($strArray);
return $arrLen;
}
$arrayWithVal = strToArray("filetest.txt"); //intermediary to pass into next function
print_r($arrayWithVal); //see what I have so far
echo "<hr />";
$newArray = $arrayWithVal;
for ($i = 1; $i < count($newArray); $i++){
for ($j = $i-1; $j >= 0; $j--){
if ($newArray[$j] > $newArray[$j+1]){ //if value on left is bigger than current value
$oldValue = $newArray[$j+1];
$newArray[$j+1] = $newArray[$j];
$newArray[$j] = $oldValue;
//return $newArray;
}
else {
break; //if value on left is smaller, skip to next position
}
}
}
print_r($newArray); //END
/*
function insertionSort($array){
$newArray=$arrayWithVal;
for($j=1; $j < count($newArray); $j++){
$temp = $newArray[$j];
$i = $j;
while(($i >= 0) && ($newArray[$i-1] > $temp)){
$newArray[$i] = $newArray[$i-1];
$i--;
}
$newArray[$i] = $temp;
}
return $array;
}
*/
/*
function insertionSort($arrData){
for ($i=1;$i<count($arrData);$i++){
for ($j=$i-1;$j>=0;$j--){
if ($arrData[$j]>$arrData[$j+1]){ //if value on left is bigger than current value
$oldValue = $arrData[$j+1];
$arrData[$j+1] = $arrData[$j];
$arrData[$j] = $oldValue;
}
else {
break; //if value on left is smaller, skip to next position
}
}
}
return $arrData;
}
*/
?>
EDIT: I should also mention that after it returns the errors, it prints the the same array that the first print_r output.
You are using array_count_values($strArray) function which will return an array using the values of $strArray as keys and their frequency in $strArray as values.
So for ex:
$arrayWithVal will be:
array('some_word'=>3,'other_word'=>4);
You are copying this array into $newArray and then later on you are trying to access $newArray with numeric index : $newArray[$j+1] while $newArray is an associative array.
That is why you are getting undefined offset error.
Exact working code for your problem can be :
//this function will pull a string from a txt file and pass characters to an array
function strToArray($file){
if ($handle = fopen($file, 'r')){
$string = fread($handle, filesize($file));
fclose($handle);
}
$strArray = str_split(preg_replace('/\s+/', '', $string)); //regex in preg_replace gets rid of all whitespaces; str_split converts string to array
$arrLen = array_count_values($strArray);
return $arrLen;
}
$arrayWithVal = strToArray("filetest.txt"); //intermediary to pass into next function
print_r($arrayWithVal); //see what I have so far
$newArray = $arrayWithVal;
$test = array();
foreach($newArray as $v){
$test[] = $v;
}
for ($i = 1; $i < count($test); $i++){
for ($j = $i-1; $j >= 0; $j--){
if ($test[$j] > $test[$j+1]){ //if value on left is bigger than current value
$oldValue = $test[$j+1];
$test[$j+1] = $test[$j];
$test[$j] = $oldValue;
//return $newArray;
}
else {
break; //if value on left is smaller, skip to next position
}
}
}
$result = array();
foreach($test as $k => $v){
$keys_array = array_keys($newArray, $v);
foreach($keys_array as $key){
$result[$key] = $v;
}
}
print_r($result);// to see $result array
If your $newArray is:
Array
(
[some] => 4
[r] => 3
[w] => 6
[t] => 1
[a] => 8
[hell] => 4
)
$result array will be :
Array
(
[t] => 1
[r] => 3
[some] => 4
[hell] => 4
[w] => 6
[a] => 8
)
Its good approach if you are learning PHP but otherwise you should just use inbuild php functions for better time performance.
I hope it helps

php array sorting with next value difference

can anyone help me with this following Array sorting
Input
$array=array(1,2,3,6,7,8,100,101,200);
Output:
$new_array=array(
0=>array(1,2,3),
1=>array(6,7,8),
2=>array(100,101),
3=>array(200)
);
Thanks in advance!
$array=array(1,2,3,6,7,8,100,101,200);
$new_array = array();
$lastNumber = '';
foreach($array as $number) {
if($lastNumber === '') {
$otherArray = array($number);
}
elseif($lastNumber + 1 !== $number) {
$new_array[] = $otherArray;
$otherArray = array($number);
}
else{
$otherArray[] = $number;
}
$lastNumber = $number;
}
$new_array[] = $otherArray;
print_r($new_array);
You can loop over the array and check the distance to the next element in the array. If this distance is larger then one add a new sub array:
$array=array(1,2,3,6,7,8,100,101,200);
$result=array(array());
for($i=0; $i<count($array)-1; $i++)
{
if($array[$i+1]-$array[$i]==1)
{
// If difference to next number is one -> push
array_push($result[count($result)-1], $array[$i]);
}
else
{
// ... else: Push and create new array for the next element
array_push($result[count($result)-1], $array[$i]);
array_push($result, array());
}
}
// Push the last number
array_push($result[count($result)-1], $array[$i]);
print_r($result);
Just a different approach with array_push()...
Pretty simple: loop through the numbers, remember the last one, if the current number is not the successor of the last one, add a new array to your result, push into the last array in your result.
$result = [];
$last = null;
foreach ($array as $number) {
if ($last !== $number - 1) {
$result[] = [];
}
$result[count($result) - 1][] = $number;
$last = $number;
}
You could even get rid of $last and directly read the last array element of the last array element of $result, but that would make the code actually more complicated.

Determining duplicate letter counts between an array of strings

I have an array of strings of random letters, and I need to know which letters are consistent between the array members. The count of the letters are important.
My method right now is loop through the array, doing a split, then looping through the spitted string to count the occurrences of each letter, then update the array with letter => count
Then do an array_reduce that creates a new array of members who only occur in all arrays. But, it's not working.
<?
$a[] = "emaijuqqrauw";
$a[] = "aaeggimqruuz";
$a[] = "aabimqrtuuzw";
$a[] = "aacikmqruuxz";
$a[] = "aacikmqruuxz";
$a[] = "aaciimqruuxy";
foreach($a as $b){
$n = str_split($b, 1);
foreach($n as $z){
$arr[$z] = substr_count($b, $z);
}
ksort($arr);
$array[] = $arr;
unset($arr);
}
$n = array_reduce($array, function($result, $item){
if($result === null){
return $item;
}else{
foreach($item as $key => $val){
if(isset($result[$key])){
$new[$key] = $val;
}
}
return $new;
}
});
foreach($n as $key => $val){
echo str_repeat($key, $val);
}
This returns aaiimqruu - which is kinda right, but there's only 2 i's in the last element of the array. There's only one i in the rest. I'm not sure how to break that down farther and get it to return aaimqruu- which I'll then pop into a SQL query to find a matching word, aquarium
There's array_intersect(), which is most likely what you'd want. Given your $a array, you'd do something like:
$a = array(.... your array...);
$cnt = count($a);
for($i = 0; $i < $cnt; $i++) {
$a[$i] = explode('', $a[$i]); // split each string into array of letters
}
$common = $a[0]; // save the first element
for($i = 1; $i < $cnt; $i++) {
$common = array_intersect($common, $a[$i]);
}
var_dump($common);
How about you do it this way? Finds out the occurrence of an item throughout the array.
function findDuplicate($string, $array) {
$count = 0;
foreach($array as $item) {
$pieces = str_split($item);
$pcount= array_count_values($pieces);
if(isset($pcount[$string])) {
$count += $pcount[$string];
}
}
return $count;
}
echo findDuplicate("a",$a);
Tested :)
Gives 12, using your array, which is correct.
Update
My solution above already had your answer
$pieces = str_split($item);
$pcount= array_count_values($pieces);
//$pcount contains, every count like [a] => 2
Seems like array_reduce is the best function for what this purpose, however I just didn't think of adding a conditional to give me the desired effect.
$new[$key] = ($result[$key] > $val) ? $val : $result[$key];
to replace
$new[$key] = $val;
did the trick.

Generating word stacks from arrays

I'm trying to do a simple word cloud exercise in PHP but with little twist. I have everything else done but I can't figure out how to do a loop that combines the words.
Here's example that will make it little bit easier to understand what I'm trying to do:
I have array like this:
$arr = array('linebreak','indent','code','question','prefer','we','programming')
Now I'm trying to do a function that starts going thru that array and gives me arrays like these:
Array(
[0] => 'linebreak'
[1] => 'linebreak indent'
[2] => 'linebreak indent code'
)
Array(
[0] => 'indent'
[1] => 'indent code'
[2] => 'indent code question'
)
So basically it goes thru the original words array word by word and makes these little arrays that has 1 to 5 next words combined.
$arr = array('linebreak','indent','code','question','prefer','we','programming');
$val = '';
foreach($arr as $key=>$value)
{
$val .= ' '.$value;
$newArr[] = $val;
}
print_r($newArr);
$a = array('linebreak','indent','code','question','prefer','we','programming');
for($i = 0; $i < count($a); $i++) {
$p = array();
for($k = $i; $k < count($a); $k++) {
$p[] = $a[$k];
$r[] = implode(' ', $p);
}
}
print_r($r);
Recursion may be the way to go. I haven't exhaustively checked the below for syntax.
function descend($arr, $offset=0) {
global $holder;
$tmp=array_slice($arr,$offset,5); //limits the result set for each starter word to 5 or fewer children
foreach($tmp as $word) {
$val .= ' '.$word;
$holder[$offset][]=$val;
}
$offset++;
if($offset<count($arr)) descend($arr,$offset);
}
$arr = array('linebreak','indent','code','question','prefer','we','programming');
$holder = descend($arr);

Categories