update
I'm new to PHP development: I looked on the PHP website for a function - array_slice. I read and looked at the example but I don't understand it. Can someone explain this in clear words for me?
I think it works as follow?
$example = array(1,2,3,4,5,6,7,8,9);
$offset = 2;
$length = 5;
$newArray = array_slice($example, offset, length);
the result of $newArray is: $newArray(3,4,5,6,7);
In addition to stefgosselin's answer that has some mistakes: Lets start with his array:
$input = array(1,2,3);
This contains:
array(3) {
[0]=> int(1)
[1]=> int(2)
[2]=> int(3)
}
Then you do array_slice:
var_dump(array_slice($input, 1));
The function will return the values after the first element (thats what the second argument, the offset means). But notice the keys!
array(2) {
[0]=> int(2)
[1]=> int(3)
}
Keep in mind that keys aren't preserved, until you pass true for the fourth preserve_keys parameter. Also because there is another length parameter before this, you have to pass NULL if you want to return everything after the offset, but with the keys preserved.
var_dump(array_slice($input, 1, NULL, true));
That will return what stefgosselin (incorrectly) wrote initially.
array(2) {
[1]=> int(2)
[2]=> int(3)
}
This function returns a subset of the array. To understand the example on the man page you have to understand array keys start at 0, ie
$array_slice = $array(1,2,3);
The above contains this:
$array[0] = 1,
$array[1] = 2,
$array[2] = 3
So, array_slice(1) of $array_sliced would return:
$arraysliced = array_slice($array_slice, 1);
$arraysliced[1] = 2;
$arraysliced[2] = 3;
It returns the part of your input array that starts at your defined offset, of the your defined length.
Think of it this way:
$output = array();
for ($i = 0; $i++; $i < count($input)) {
if ($i < $start)
continue;
if ($i > $start + $length)
break;
$output[] = $input[$i];
}
Basically its an skip and take operation. Skip meaning to jump to that element. Take meaning how many.
PHP has a built - in function, array_slice() , that you can use to extract a range of elements from an
array. To use it, pass it the array to extract the slice from, followed by the position of the first element in
the range (counting from zero), followed by the number of elements to extract. The function returns a new
array containing copies of the elements you extracted (it doesn ’ t touch the original array). For example:
$authors = array( “Steinbeck”,
“Kafka”, “Tolkien”, “Dickens” );
$authorsSlice = array_slice(
$authors, 1, 2 ); // Displays “Array
( [0] = > Kafka [1] = > Tolkien )”
print_r( $authorsSlice );
By the way, if you leave out the third argument to array_slice() , the function extracts all elements
from the start position to the end of the array:
$authors = array( “Steinbeck”, “Kafka”, “Tolkien”, “Dickens” );
$authorsSlice = array_slice( $authors, 1 );
// Displays “Array ( [0] = > Kafka [1] = > Tolkien [2] = > Dickens )”;
print_r( $authorsSlice );
Earlier you learned that array_slice() doesn ’ t preserve the indices of elements taken from an indexed
array. If you want to preserve the indices, you can pass a fourth argument, true , to array_slice() :
$authors = array( “Steinbeck”, “Kafka”, “Tolkien”, “Dickens” );
// Displays “Array ( [0] = > Tolkien [1] = > Dickens )”;
print_r( array_slice( $authors, 2, 2 ) );
// Displays “Array ( [2] = > Tolkien [3] = > Dickens )”;
print_r( array_slice( $authors, 2, 2, true ) );
Related
I want to split the following string into 3-letter elements. Additionally, I want all elements to have 3 letters even when the number of characters in the inout string cannot be split evenly.
Sample string with 10 characters:
$string = 'lognstring';
The desired output:
$output = ['log','nst','rin','ing'];
Notice how the in late in the inout string is used a second time to make the last element "full length".
Hope this help you.
$str = 'lognstring';
$arr = str_split($str, 3);
$array1= $arr;
array_push($array1,substr($str, -3));
print_r($array1);
$str = 'lognstring';
$chunk = 3;
$arr = str_split($str, $chunk); //["log","nst","rin","g"]
if(strlen(end($arr)) < $chunk) //if last item string length is under $chunk
$arr[count($arr)-1] = substr($str, -$chunk); //replace last item to last $chunk size of $str
print_r($arr);
/**
array(4) {
[0]=>
string(3) "log"
[1]=>
string(3) "nst"
[2]=>
string(3) "rin"
[3]=>
string(3) "ing"
}
*/
Differently from the earlier posted answers that blast the string with str_split() then come back and mop up the last element if needed, I'll demonstrate a technique that will populate the array of substrings in one clean pass.
To conditionally reduce the last iterations starting point, either use a ternary condition or min(). I prefer the syntactic brevity of min().
Code: (Demo)
$string = 'lognstring';
$segmentLength = 3;
$totalLength = strlen($string);
for ($i = 0; $i < $totalLength; $i += $segmentLength) {
$result[] = substr($string, min($totalLength - $segmentLength, $i), $segmentLength);
}
var_export($result);
Output:
array (
0 => 'log',
1 => 'nst',
2 => 'rin',
3 => 'ing',
)
Alternatively, you can prepare the string BEFORE splitting (instead of after).
Code: (Demo)
$extra = strlen($string) % $segmentLength;
var_export(
str_split(
$extra
? substr($string, 0, -$extra) . substr($string, -$segmentLength)
: $string,
$segmentLength
)
);
I have an array:
Array
(
[0] => Alex
[1] => Michael
[2] => Harry
[3] => Dave
[4] => Michael
[5] => Victor
[6] => Harry
[7] => Alex
[8] => Mary
[9] => Mary
)
I want to write to a function that will return an array with elements that most number of time repeated. For example, the output array should have Alex, Micheal, Hary, and Mary because each one of them is repeated twice. IF Alex was repeated three times, then the output array should only have Alex.
function writeIn($ballot) {
$count = array_count_values($ballot);
arsort($count);
foreach($count as $c => $name) {
$arr[] = $name;
}
}
Three problems with your current function.
$name and $c are reversed in the foreach loop. The names will be the keys
The loop doesn't stop after it gets the top counts
The function doesn't return anything.
You can fix it like this:
After you count and sort with
$count = array_count_values($ballot);
arsort($count);
you can get the max value by taking the first value from the rsorted counts.
$max = reset($count);
Then as you iterate, when you reach a name with a count !== the max count, break out of the loop.
foreach($count as $name => $c) {
if ($c !== $max) break;
$arr[] = $name;
}
And don't forget to return the result.
return $arr;
Another possibility is to use some built-in PHP functions. I agree starting with array_count_values() seems like a good idea.
$count = array_count_values($ballot);
After that you can get the max count using max()
$max = max($count);
Filter the counts to return only items with the max count
$top = array_filter($count, function($n) use ($max) {
return $n == $max;
});
// PHP 7.4 version
// $top = array_filter($count, fn($n) => $n == $max);
And return the keys from that array to get the names.
return array_keys($top);
This solution keeps track as it goes.
function writeIn($ballot) {
$tally = []; // How many votes did each person get
$choice = []; // List of names with max occurrences
$max = 0;
array_walk($ballot, function($item) use(&$choice, &$tally, &$max) {
if ( ! array_key_exists($item, $tally) ) {
// If we haven't seen this name, add it with a count of 1
$tally[$item] = 1;
} else {
// We saw this name already so increment its count
$tally[$item]++;
}
// Check to see if the current name has exceeded or reached max
if ( $tally[$item] > $max ) {
// This is a new max so replace the choice list with this name
$choice = [$item];
$max = $tally[$item];
} elseif ( $tally[$item] == $max ) {
// This name has reached the current max so add it to the list
$choice[] = $item;
}
});
// Now we have the list of names with the most occurrences.
return $choice;
}
Don't Panic's answer is a good one. There is also an optional search parameter to array_keys() to pass a search parameter which is applicable to this problem. Once you have the results sorted by count, and you know the max count, you can use that parameter to only return keys(name)s that match the associated count value.
<?php
$ballot = ['Alex', 'Michael', 'Harry', 'Dave', 'Michael', 'Victor', 'Harry', 'Alex', 'Mary', 'Mary'];
function writeIn($ballot) {
$count = array_count_values($ballot);
arsort($count);
$max = reset($count);
return array_keys($count, $max);
}
var_dump( writeIn($ballot));
Returns:
array(4) {
[0]=>
string(4) "Alex"
[1]=>
string(7) "Michael"
[2]=>
string(5) "Harry"
[3]=>
string(4) "Mary"
}
I have a string which has "23:22:0"
$string = "23:22:0";
$array = explode(":", $string);
if ($array[0] == 0) {
$array[0] = 1;
}
if ($array[1] == 0) {
$array[1] = 1;
}
if ($array[2] == 0) {
$array[2] = 1;
}
How to avoid multiple if condition check here and i need this condition to be optimised in some best way. Any help is appreciated thanks in advance.
Please check below example. I have commented out your $string variable and tested $string with '0:0:0' value.
Added print_r() to check whether the value is correct or not as we are expecting.
Hope it might be helpful.
//$string = "23:22:0";
$string = "0:0:0";
$array = explode(":", $string);
$array = array(
0 => ($array[0] == 0) ? 1 : $array[0],
1 => ($array[1] == 0) ? 1 : $array[1],
2 => ($array[2] == 0) ? 1 : $array[2],
);
print_r($array);
I wrote this answer because I thought there was an unknown number of items.
OP has now clarified that it's always three items. This is probably a bit overkill for the task at hand.
You can create a new array with 1's and use array_replace to merge it with the original array if you first remove the zero values.
$string = "23:22:0";
$array = explode(":", $string);
$fill = array_fill(0,count($array), 1); //create new array [1,1,1]
$array= array_filter($array); // remove zero values
$array= array_replace($fill,$array); // "merge" the arrays
var_dump($array);
Output:
array(3) {
[0]=>
string(2) "23"
[1]=>
string(2) "22"
[2]=>
int(1)
}
https://3v4l.org/thpfU
With three items in mind you can make the code look better with a loop.
It will perform about the same I believe.
foreach($array as &$val){
if(!$val) $val=1;
}
I have two dynamic variables
$numberOfX = 2;
and
$numberOfY = 5;
The challenge for me is that I need to divide the number 5(numberOfY) between 2(numberOfX). That's an issue cause I will either through a calculation(divide) get a floating number like 2,5 or I can choose (ceil) to round it up but then I get 3(and totally it will be more then 5, namely 6).
I need a whole integers with no decimals. But still it can't be more or less then 5.
So ideally I Would like an array e.g with 3 and 2 in it. As it added will give 5.
How can I do this in PHP , remembering that numberOfX and numberOfY can be any number ?
$numberOfX = 3;
$numberOfY = 5;
$result = array_fill(0, $numberOfX, (int) floor($numberOfY / $numberOfX));
$i = 0;
while (array_sum($result) !== $numberOfY) {
$result[$i++]++;
}
var_dump($result, array_sum($result));
Demo
$numberOfX = 2;
$numberOfY = 5;
$intDivisionValues[] = intval($numberOfY/$numberOfX);
$intDivisionValues[] = $numberOfY - intval($numberOfY/$numberOfX);
$intDivisionValues will then be:
Array
(
[0] => 2
[1] => 3
)
Your question is not completely clear about the algorithm you are looking for. I guess this might come close:
<?php
$numberOfX = 2;
$numberOfY = 5;
$full = intval($numberOfY / $numberOfX);
$part = intval($numberOfY % $numberOfX);
$output = array_fill(1, $numberOfX-1, $full);
$output[] = $full+$part;
var_dump($output);
The output for the example values would be:
array(2) {
[0] =>
int(2)
[1] =>
int(3)
}
For an example using different values, especially different values for $numberOfX the result would be different, obviously. Here the output for values 3 and 31:
array(3) {
[0] =>
int(10)
[1] =>
int(10)
[2] =>
int(11)
}
You can play around with other values to see if that suits your needs...
This algorithm behaves different to what #WilliamJanoti suggests in his answer. As said: your question is not really clear in what you are looking for...
<?php
$a = array(1, 2, 3, 4, 5);
foreach ($a as $key => $elem) {
echo "$key = $elem"; echo ' = ';
var_dump(current($a));\
}
?>
The output I get when running that is as follows:
0 = 1 = int(2)
1 = 2 = int(2)
2 = 3 = int(2)
3 = 4 = int(2)
4 = 5 = int(2)
Seems to me that this is the output I should be getting?:
0 = 1 = int(1)
1 = 2 = int(2)
2 = 3 = int(3)
3 = 4 = int(4)
4 = 5 = int(5)
I do current() before the for loop on $a and get int(1). Thus it seems like it's the foreach loop that's causing it to increment. But if that's the case why is it only doing it once?
If I call next() in the for loop it increments but not otherwise. Of course next() starts out at int(3) (ie. the value after int(2))..
From reading the PHP documention on current, it does not look like you should expect foreach to move the current pointer.
Please see:
http://php.net/manual/en/function.current.php
What's a bit confusing is that the each function does move the current pointer. So if you rewrite your array as a loop using each rather than foreach, then you will get the desired current behavior.
Here's your example rewritten with each(), which produces the expected results:
<?php
$a = array(1, 2, 3, 4, 5);
while ( list($key,$elem) = each($a)) {
echo "$key = $elem"; echo ' = ';
var_dump(current($a));
}
?>
current() uses the internal flag (pointer) and foreach uses it's own.
If you want to do this (which is kind of silly as you have the key in $key) you can use ArrayIterator
I just stumbled on the same problem, and I believe I have a theory.
Foreach doesn't access the array elements by value, it creates its own copy. However, while doing this, it increments the value returned by current() just once.
To check this:
<?php
$a = [0, 1, 2];
foreach ($a as &$val){ // accessing the array elts by reference this time
var_dump(current($a));
}
/*this outputs:
int(1)
int(2)
bool(false)*/