Generating word stacks from arrays - php

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);

Related

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

Expand array of numbers and hyphenated number ranges to array of integers [duplicate]

This question already has answers here:
Populate array of integers from a comma-separated string of numbers and hyphenated number ranges
(8 answers)
Closed 6 months ago.
I'm trying to normalize/expand/hydrate/translate a string of numbers as well as hyphen-separated numbers (as range expressions) so that it becomes an array of integer values.
Sample input:
$array = ["1","2","5-10","15-20"];
should become :
$array = [1,2,5,6,7,8,9,10,15,16,17,18,19,20];
The algorithm I'm working on is:
//get the array values with a range in it :
$rangeArray = preg_grep('[-]',$array);
This will contain ["5-10", "16-20"]; Then :
foreach($rangeArray as $index=>$value){
$rangeVal = explode('-',$value);
$convertedArray = range($rangeVal[0],$rangeVal[1]);
}
The converted array will now contain ["5","6","7","8","9","10"];
The problem I now face is that, how do I pop out the value "5-10" in the original array, and insert the values in the $convertedArray, so that I will have the value:
$array = ["1","2",**"5","6","7","8","9","10"**,"16-20"];
How do I insert one or more values in place of the range string? Or is there a cleaner way to convert an array of both numbers and range values to array of properly sequenced numbers?
Here you go.
I tried to minimize the code as much as i can.
Consider the initial array below,
$array = ["1","2","5-10","15-20"];
If you want to create a new array out of it instead $array, change below the first occurance of $array to any name you want,
$array = call_user_func_array('array_merge', array_map(function($value) {
if(1 == count($explode = explode('-', $value, 2))) {
return [(int)$value];
}
return range((int)$explode[0], (int)$explode[1]);
}, $array));
Now, the $array becomes,
$array = [1,2,5,6,7,8,9,10,15,16,17,18,19,20];
Notes:
Casts every transformed member to integer
If 15-20-25 is provided, takes 15-20 into consideration and ignores the rest
If 15a-20b is provided, treated as 15-20, this is result of casing to integer after exploded with -, 15a becomes 15
Casts the array keys to numeric ascending order starting from 0
New array is only sorted if given array is in ascending order of single members and range members combined
Try this:
<?php
$array = ["1","2","5-10","15-20"];
$newdata = array();
foreach($array as $data){
if(strpos($data,'-')){
$range = explode('-', $data);
for($i=$range[0];$i<=$range[1];$i++){
array_push($newdata, $i);
}
}
else{
array_push($newdata, (int)$data);
}
}
echo "<pre>";
print_r($array);
echo "</pre>";
echo "<pre>";
print_r($newdata);
echo "</pre>";
Result:
Array
(
[0] => 1
[1] => 2
[2] => 5-10
[3] => 15-20
)
Array
(
[0] => 1
[1] => 2
[2] => 5
[3] => 6
[4] => 7
[5] => 8
[6] => 9
[7] => 10
[8] => 15
[9] => 16
[10] => 17
[11] => 18
[12] => 19
[13] => 20
)
Problem solved!
Using range and array_merge to handle the non-numeric values:
$array = ["1","2","5-10","15-20"];
$newArray = [];
array_walk(
$array,
function($value) use (&$newArray) {
if (is_numeric($value)) {
$newArray[] = intval($value);
} else {
$newArray = array_merge(
$newArray,
call_user_func_array('range', explode('-', $value))
);
}
}
);
var_dump($newArray);
It's easier to find out the minimum and maximum value and create the array with them. Here's an example:
$in = ["1","2","5-10","15-20"];
$out = normalizeArray($in);
var_dump($out);
function normalizeArray($in)
{
if(is_array($in) && sizeof($in) != 0)
{
$min = null;
$max = null;
foreach($in as $k => $elem)
{
$vals = explode('-', $elem);
foreach($vals as $i => $val)
{
$val = intval($val);
if($min == null || $val < $min)
{
$min = $val;
}
if($max == null || $val > $max)
{
$max = $val;
}
}
}
$out = array();
for($i = $min; $i <= $max; $i++)
{
$out[] = $i;
}
return $out;
}
else
{
return array();
}
}
here you go mate.
<?php
$array = ["1","2","5-10","15-20"];
$newArr = array();
foreach($array as $item){
if(strpos($item, "-")){
$temp = explode("-", $item);
$first = (int) $temp[0];
$last = (int) $temp[1];
for($i = $first; $i<=$last; $i++){
array_push($newArr, $i);
}
}
else
array_push($newArr, $item);
}
print_r($newArr);
?>
Simpler and shorter answer.
See in Ideone
$new_array = array();
foreach($array as $number){
if(strpos($number,'-')){
$range = explode('-', $number);
$new_array = array_merge($new_array, range($range[0],$range[1]));
}
else{
$new_array[] = (int) $number;
}
}
var_dump($new_array);
try this:
$array = ["1","2","5-10","15-20"];
$result = [];
foreach ($array as $a) {
if (strpos($a,"-")!== false){
$tmp = explode("-",$a);
for ($i = $tmp[0]; $i<= $tmp[1]; $i++) $result[] = $i;
} else {
$result[] = $a;
}
}
var_dump($result);
you did not finish a little
$array = ["1","2","5-10","15-20"];
// need to reverse order else index will be incorrect after inserting
$rangeArray = array_reverse( preg_grep('[-]',$array), true);
$convertedArray = $array;
foreach($rangeArray as $index=>$value) {
$rangeVal = explode('-',$value);
array_splice($convertedArray, $index, 1, range($rangeVal[0],$rangeVal[1]));
}
print_r($convertedArray);

How to sort a string by length of its words in php without using functions?

I have been asked a question in an interview to sort a string by length of its words in php without using built in functions.No idea how to do this. Can somebody help me with this?
String: Sort a string by length of its words
Thanks in advance
$array = array('harish', 'mohan', 'jaideep', 'hari');
for ($i = 1; $i < count($array); $i++) {
for ($j = $i; $j > 0; $j--) {
if (strlen($array[$j]) < strlen($array[$j - 1])) {
$tmp = $array[$j];
$array[$j] = $array[$j - 1];
$array[$j - 1] = $tmp;
}
}
}
var_dump($array);
you could try this:
$string = "this is my test string";
$array = explode(" ", $string);
$result = array();
foreach ($array as $key => $string){
$counter = 0;
for($i = 0;;$i++){
if (!isset($string[$i])){
break;
}
$counter++;
}
$result[$counter][] = $string;
}
This splits your string and puts it into an array, where the keys are the counted characters. The problem now is, that you need to sort the array by the keys, which can be acquired by using ksort.
I do not know if you may use it, if not, refer to this answer (use of sort) or this answer (no sort), this should do the trick (though I didn't test it).
This is the solution that I propose. I added some comments.
<?php
/* First part split the string in their words and store them in an array called $words.
* The key is the length of the word and the value is an array with all the words having the same length as the key.
* e.g
* Array
(
[4] => Array( [0] => Sort )
[1] => Array( [0] => a )
[6] => Array( [0] => string, [1] => length)
[2] => Array( [0] => by, [1] => of)
[3] => Array( [0] => its )
)
*/
$str = "Sort a string by length of its words";
$word = '';
$i = 0;
$word_length = 0;
$words = [];
$max = -1;
while( isset($str[$i]) ) {
if( $str[$i] !== ' ' ){
$word .= $str[$i];
$word_length++;
}else{
//This is going to save the size of the longhest word in the array:
$max = ($word_length > $max) ? $word_length : $max;
//store the
$words[$word_length][] = $word;
$word = '';
$word_length = 0;
}
$i++;
}
//print_r($words); // uncomment this if you wanna see content of the array.
//The if-condition is for ascending order or descending order.
$order = "DESC"; // "ASC" | "DESC"
$res = '';
if( $order === "DESC") {
for( $i = $max; $i>=0 ; $i--) {
if( ! isset($words[$i]) ) { continue; }
foreach($words[$i] as $word){
$res .= $word . ' ';
}
}
}else {
//ascending order:
for( $i = 0; $i<=$max; $i++) {
if( ! isset($words[$i]) ) { continue; }
foreach($words[$i] as $word){
$res .= $word . ' ';
}
}
}
echo $res . "\n";
?>
Is this what you want?
Note: isset, echo, print, etc are PHP language constructs whereas print_r(), strlen(), etc. are built in functions. If you have doubts, you can see what's the difference in this post. What is the difference between a language construct and a "built-in" function in PHP?

adding previous array values to newer array values

$test = 'test1/test2/test3/test4';
I am trying to get a array from that $test above which i'd like to output like below.
Array
(
[0] => /
[1] => /test1/
[2] => /test1/test2/
[3] => /test1/test2/test3/
[4] => /test1/test2/test3/test4/
)
I've tried loops but can't quite figure out how to get it quite right.
Try to make loop like :
$test = 'test1/test2/test3/test4';
$test_arr = explode("/", $test);
$test_size = count($test_arr);
$count = 1;
$new_test_arr = array('/');
for ($i=0; $i<$test_size; $i++)
{
$new_test_arr[$count] = $new_test_arr[$i] . $test_arr[$i] . "/"
$count++;
}
Here's a way to do it very compactly:
$parts = explode("/", $test);
for($i = 0; $i <= count($parts); ++$i) {
echo "/".implode("/", array_slice($parts, 0, $i))."\n";
}
Not terribly efficient, but I don't think efficiency would matter in something trivial you 'd only do once. On the plus side, the loop modifies no variables which makes it easier to reason about.
See it in action.
A very easy and simple way, for this case would be
$test = 'test1/test2/test3/test4';
$arr = explode("/", $test);
$t = "";
$newArray = array("/");
foreach($arr as $value) {
$t .= "/".$value;
$newArray[] = $t;
}
print_r($newArray);
Demo

Fixing Permute Output

Hey there I've made a recursive permutation function for class, but I output is less than favorable.
http://codepad.org/DOaMP9oc
function permute($arr) {
$out = array();
if (count($arr) > 1) {
$i = 0;
foreach($arr as $r => $c) {
$n = $arr;
unset($n[$r]);
$out[$c] = permute($n);
}
}
else
return array_shift($arr);
return $out;
}
If input is array(1,2,3,4,5), Output is:
Array
(
[1] => Array
(
[2] => Array
(
[3] => Array
(
[4] => 5
[5] => 4
)
[4] => Array
(
[3] => 5
[5] => 3
)
[5] => Array
(
[3] => 4
[4] => 3
)
)
ETC......................
This is all Correct, you can read it like this key.key.key.key.value or 12345,12354,12435
Currently, to convert this output to something readable, I'm using this ugly block of code:
http://codepad.org/qyWcRBCl
foreach($out as $k => $a)
foreach($a as $l => $b)
foreach ($b as $m => $c)
foreach ($c as $n => $d)
echo $k.$l.$m.$n.$d.'<br>';
How can I alter my function to eliminate the foreach stack and output in a similar format from permute().
My solution is to work on strings:
function permute($string) {
if (strlen($string)<2) {
return array($string);
}
$permutations = array();
// Copy everything but the first character of the string.
$copy = substr($string, 1);
foreach (permute($copy) as $permutation) {
$length = strlen($permutation);
// Insert the first character of the original string.
for ($i=0; $i<=$length; $i++) {
$permutations[] = substr($permutation, 0, $i) . $string[0] . substr($permutation, $i);
}
}
sort($permutations);
return $permutations;
}
header('Content-type:text/plain');
print_r(permute('12345'));
You already have a working implementation so I have no qualms in giving that to you. Note that the array is not created in order, so I simply sort it at the end. Also note that this only works on things that you intend to have the value of 1 character, so doing a permutation of car names would not work.
Even if you don't like this answer, I suggest that you use a type-hint for array:
function permute(array $arr) {
This will enforce that you pass an array into it.
function display_permutation($array){
if(is_array($array)){
foreach($array as $key => $val){
echo $key;
display_permutation($val);
}
}else{
echo $array;
}
}
Here is my permutation function and we can display results in simple way
class Permute {
public $results = Array();
public function __construct(array $array) {
$this->_permute($array);
}
private function _permute(array $orig, array $perm = Array()) {
if(!count($orig)) {
$this->results[] = $perm;
return null;
}
$count = count($orig);
for($i = 0; $i < $count; ++$i) {
$orig2 = $orig;
unset($orig2[$i]);
$orig2 = array_values($orig2);
$perm2 = $perm;
$perm2[] = $orig[$i];
$this->_permute($orig2, $perm2);
}
}
}
$arr = Array(1,2,3,4,5);
$permute = new Permute($arr);
foreach($permute->results as $result) {
echo join('', $result).'<br>';
}
I opted to use the following function:
function showPerms($a,$i='') {
if (is_array($a))
foreach($a as $k => $v)
showPerms($v,$i.$k);
else
echo $i.$a."\n";
}
However, I'd still like to do this in a singular recursive function.

Categories