Determine if the array has negative numbers and change them to zero - php

I have wrote this code:
$final = array(
($data[0] - $data[1]),
($data[1] - $data[2]),
($data[2] - $data[3]),
($data[3] - $data[4]),
($data[4] - $data[5]),
($data[5] - $data[6])
);
Some of them will return negative numbers (-13,-42 etc...), how to change the negative ones to 0?
By the way the think i do after is:
$data_string = join(",", $final);
Example: I need to convert it like in the following:
1,3,-14,53,23,-15 => 1,3,0,53,23,0

You can map that:
$zeroed = array_map(function($v) {return max(0, $v);}, $final);
Will set all numbers lower than 0 to 0.
See array_map and max.
Additionally, you can save you some more handwriting with $data:
$final = array_reduce($data, function($v, $w)
{
static $last;
if (null !== $last) $v[] = max(0, $last - $w);
$last = $w;
return $v;
}, array());
$data_string = join(",", $final);
See array_reduce.
Edit: A foreach loop might be easier to follow, I added some comments as well:
// go through all values of data and substract them from each other,
// negative values turned into 0:
$last = NULL; // at first, we don't have a value
$final = array(); // the final array starts empty
foreach($data as $current)
{
$isFirst = $last === NULL; // is this the first value?
$notFirst = !$isFirst;
if ($notFirst)
{
$substraction = $last - $current;
$zeroed = max(0, $substraction);
$final[] = $zeroed;
}
$last = $current; // set last value
}
And here is the demo.

Am guessing this is homework. If so please mark it as such.
Hints:
use a loop instead of hardwired array references.
use an if-statement to check for negative values and switch their sign.
your use of join is correct

I like Hakre's compact answer. However, if you have a more complex requirement, you can use a function:
<?php
$data = array(11,54,25,6,234,9,1);
function getZeroResult($one, $two) {
$result = $one - $two;
$result = $result < 0 ? 0 : $result;
return $result;
}
$final = array(
getZeroResult($data[0], $data[1]),
getZeroResult($data[1], $data[2]),
getZeroResult($data[2], $data[3]),
getZeroResult($data[3], $data[4]),
getZeroResult($data[4], $data[5]),
getZeroResult($data[5], $data[6])
);
print_r($final);
?>
http://codepad.org/viGBYj4f (With an echo to show the $result before test.)
Which gives you:
Array
(
[0] => 0
[1] => 29
[2] => 19
[3] => 0
[4] => 225
[5] => 8
)
Note, you could also just return the ternary:
function getZeroResult($one, $two) {
$result = $one - $two;
return $result < 0 ? 0 : $result;
}
As well as using it in a loop:
<?php
$data = array(11,54,25,6,234,9,1);
function getZeroResult($one, $two) {
$result = $one - $two;
echo "$one - $two = $result\n";
return $result < 0 ? 0 : $result;
}
$c_data = count($data)-1;
$final = array();
for ($i = 0; $i < $c_data; $i++) {
$final[] = getZeroResult($data[$i], $data[$i+1]);
}
print_r($final);
?>
http://codepad.org/31WCbpNr

Related

How to add string into array in PHP?

I have these for loop to determine consecutive number. What I achieve so far is to print the output in string.
$arr = [1,2,3,6,11,5,4,8,9,3];
for($start=0; $start<=count($arr); $start++){
for($end=$start+1; $end<=count($arr); $end++){
$total = $arr[$end] - $arr[$start];
if($total == 1){
echo 'Number is '.$arr[$start].','.$arr[$end].'<br/>';
} else {
echo '';
}
$arr[$start++];
}
}
My goal is to add the output into array.
I tried to use multidimensional array but no output display.
$arr = [1,2,3,6,11,5,4,8,9,3];
$arr3 = [];
for($start=0; $start<=count($arr); $start++){
for($end=$start+1; $end<=count($arr); $end++){
$total = $arr[$end] - $arr[$start];
if($total == 1){
$arr2 = array();
$arr2[] = $arr[$start].','.$arr[$end].'';
$arr3[] = $arr2;
} else {
}
$arr[$start++];
}
}
echo '<pre>';
print_r($arr3);
echo '</pre>';
exit;
Appreciate if someone can help me. Thanks.
you can simply use array functions, if sorting is important to you as #nice_dev said, you must sort your array before.
$arr = [1,2,3,6,11,5,4,8,9,3];
$cons = [] ;
while (array_key_last($arr) != key($arr)) {
if ((current($arr)+1) == next($arr)) {
prev($arr);
$cons[] = current($arr) . ',' . next($arr);
}
}
print_r($cons);
the output will be :
Array
(
[0] => 1,2
[1] => 2,3
[2] => 8,9
)
You can better sort() the input array first. This way, collecting all consecutive elements would get much simpler. If value at any index isn't +1 of the previous one, we add the $temp in our $results array and start a new $temp from this index.
Snippet:
<?php
$arr = [1,2,3,6,11,5,4,8,9,3];
$result = [];
sort($arr);
$temp = [];
for($i = 0; $i < count($arr); ++$i){
if($i > 0 && $arr[ $i ] !== $arr[$i - 1] + 1){
$result[] = implode(",", $temp);
$temp = [];
}
$temp[] = $arr[$i];
if($i === count($arr) - 1) $result[] = implode(",", $temp);
}
print_r($result);
Online Demo

Return the number of all unique case-insensitive characters

I am trying create a function which returns the number of all unique case-insensitive
characters that occur >= $n times in a given string.
For example:
function getNumOfUniqueCharacters($str, $n) {
// ...
}
getNumOfUniqueCharacters('A1B2C3', 2); // 0
getNumOfUniqueCharacters('A1a1C1', 2);
// 2, because A and 1 both occur 2 or more times.
getNumOfUniqueCharacters('Alabama', 3); // 1
I did this:
function getNumOfUniqueCharacters($text)
{
$ret = 0;
$a = [];
$t = str_split(strtolower($text));
$l = count($t);
for ($i = 0; $i < $l; $i++) {
$c = $t[$i];
if (array_key_exists($c, $t)) {
if ($t[$c] === 1)
$ret += 1;
$t[$c] += 1;
} else {
$t[$c] = 1;
}
}
return $ret;
}
But it does not work so good, I need to add second argument $n.
How to add it correctly?
I hope I got your question right.
Here's my idea for this code:
<?php
$string = "A1B2C1A2b2b4b5";
function getNumOfUniqueCharacters($string, $n)
{
$occurrenceArray = array();
$text = str_split(strtolower($string));
//put each character in a keyValue array and count them
foreach($text as $character){
if(!array_key_exists($character, $occurrenceArray)) $occurrenceArray[$character] = 1;
else $occurrenceArray[$character]++;
}
//loop through keyValue array and remove everything that has value < $n
foreach($occurrenceArray as $key => $value)
{
if($value < $n) unset($occurrenceArray[$key]);
}
//return array
return $occurrenceArray;
}
print_r(getNumOfUniqueCharacters($string, 2));
This code right here will print the following:
Array (
[a] => 2
[1] => 2
[b] => 4
[2] => 3 )
Edit: If you need the count of how many characters repeat more than $n, you can simply replace the return with return count($occurrenceArray);
This task is pretty easy, if you use array functions of PHP:
function getNumOfUniqueCharacters(string $string = '', int $n = 1): int {
// Split the string by character and count the occurences of all values
$counted = array_count_values(mb_str_split(mb_strtolower($str)));
// Discard everything, that is does not match the $n parameter
$counted = array_filter($counted, function($a) use($n) {
return $a >= $n;
});
// Return the length of the remaining array
return count($counted);
}
Also note, that you may use mb_* functions, so your code will work with multibyte characters.
I have written you a function with a lot of comments to explain the thought process,
function getNumOfUniqueCharacters($string, $n = null) {
// Map all case-insensitive characters to an array
$map = str_split(strtolower($string), 1);
// Character registry
$reg = array_count_values($map);
// Filter out single occurances
$reg = array_filter($reg, function($v){return $v > 1;});
// Filter out less than $n occurances (if $n is not null)
if (null !== $n) {
$reg = array_filter($reg, function($v)use($n){return $v >= $n;});
}
// Return the number duplicate occurances (or more than n occurances)
return count($reg);
}
Usage:
echo getNumOfUniqueCharacters('A1B2C3', 2) . PHP_EOL;
echo getNumOfUniqueCharacters('A1a1C1', 2) . PHP_EOL;
echo getNumOfUniqueCharacters('Alabama', 3) . PHP_EOL;
echo getNumOfUniqueCharacters('Mississippi') . PHP_EOL;
Output:
0
2
1
3

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

User defined sort and filtering of a string array

Lets say I have the following data:
$data = array('av','ds','tg','ik','pk','np','rq');
I'm having trouble finding out what tools to use to get the range of strings between two variables.
function sortrange ( $a, $b, $data )
{
return $range;
}
For example:
sortrange('ds','np', $data);
Would return
array('ds','tg','ik','pk','np');
I would also like it be able to do backwards sorting, for example:
sortrange('np','tg');
Would return:
array('np','pk','ik','tg');
The closest function I found that might be usable was usort, but it couldn't get anywhere close to what I wanted.
Thanks for any help in advance. :)
Note: The following function will just use the first occurance of $start and $end. If they repeat, the behavior may not be what you expect.
function subset_range($array, $start, $end) {
$start_index = array_search($start, $array);
$end_index = array_search($end, $array);
$min = min($start_index, $end_index);
$max = max($start_index, $end_index);
$ret = array_slice($array, $min, $max - $min + 1);
return $start_index < $end_index ? $ret : array_reverse($ret);
}
$data = array('av','ds','tg','ik','pk','np','rq');
print_r(subset_range($data, 'ds', 'np'));
print_r(subset_range($data, 'np', 'tg'));
Output:
Array
(
[0] => ds
[1] => tg
[2] => ik
[3] => pk
[4] => np
)
Array
(
[0] => np
[1] => pk
[2] => ik
[3] => tg
)
Something like this:
function get_subset($a, $b, $data) {
// fail if $a or $b is not present in $data
if(in_array($a) === false || in_array($b) === false) {
return false;
}
// get the index of both $a and $b
$i_a = array_search($a, $data);
$i_a = array_search($b, $data);
$result = array();
if($i_a < $i_b) {
// if $a is earlier than $b in $data, loop forward
for($i = $i_a; $i <= $i_b; $i++) {
$result[] = $data[$i];
}
} elseif($i_a > $i_b) {
// if $a is later than $b in $data, loop backward
for($i = $i_a; $i <= $i_b; $i--) {
$result[] = $data[$i];
}
} else {
// if $a and $b are the same
return array($a, $b);
}
return $result;
}

Categories