Make an array divisible by n? - php

I have an array:
$arr = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
Is there a way to make it contain elements only divisible by 3 (or n)? So in the above example g would be removed as it's left over from a division of 3?
EDIT
I want amount of elements divisible by 3.

You can use a combination of array_slice(), count() and modulus (%) to get the array evenly divisible:
$arr_length = count($arr);
$new_arr = array_slice($arr, 0, $arr_length - ($arr_length % 3));

Sounds like you want the length to be divisible by 3 and you want to remove elements until that happens. array_slice can help you out here.
$to_remove = count($arr) % 3;
if($to_remove > 0){
$arr = array_slice($arr, 0, -$to_remove);
}

#panthro simply try with for loop like below and use array_pop()
<?php
$arr = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
if(count($arr) % 3 != 0){
$remainder = count($arr) % 3;
for($i=0;$i < $remainder;$i++){
array_pop($arr);
}
}
echo "<pre>";
print_r($arr); //final array divisible by 3

Related

How to increment a string with a custom character set

Given a custom alphabet like ['f', 'h', 'z', '#', 's']
I'd like to take a string written in this "alphabet" like
ffff#zz and increment it
So for example if the string was sss After incrementing it will look like hfff the same way that if you increment 999 you get 1000
My current attempt is here: https://3v4l.org/FjAsd
Given:
$characters = ['a', 'b', 'c'];
$string = 'cccc';
my code can do:
baaaa
but if give it
$characters = ['a', 'b', 'c'];
$string = 'aaa';
it will return
b
When I expected aab
The way this works is by processing the string from the end, each time you look at a character you check it's position in the array (I use a flipped array as it's more efficient than using array_search() each time). Then if the character is at the end of the array, then set it to the 0th element of the alphabet and increment the next digit to the left. If there is another letter from the alphabet to increment the current value, then just replace it and stop the loop.
The last bit is that if you have processed every character and the loop was still going, then there is a carry - so add the 0th digit to the start.
$characters = ['a', 'b', 'c'];
$string = 'cccc';
$index = array_flip($characters);
$alphabetCount = count($index)-1;
for ( $i = strlen($string)-1; $i >= 0; $i--) {
$current = $index[$string[$i]]+1;
// Carry
if ( $current > $alphabetCount ) {
$string[$i] = $characters[0];
}
else {
// update and exit
$string[$i] = $characters[$current];
break;
}
}
// As reached end of loop - carry
if ( $i == -1 ) {
$string = $characters[0].$string;
}
echo $string;
gives
aaaaa
with
$characters = ['f', 'h', 'z', '#', 's'];
$string = 'ffff#zz';
you get
ffff#z#
I ended up with something like this:
$string = 'ccc';
$alphabet = ['a', 'b', 'c'];
$numbers = array_keys($alphabet);
$numeric = str_replace($alphabet, $numbers, $string);
$base = count($alphabet) + 1;
$decimal = base_convert($numeric, $base, 10);
$string = base_convert(++$decimal, 10, $base);
strlen($decimal) !== strlen($string)
and $string = str_replace('0', '1', $string);
echo str_replace($numbers, $alphabet, $string);
This one has the advantage of supporting multi byte characters

Get multiple max variable name

I have 6 variables and each other have integer values, I want to get the variable name which have the greatest value.
The variables are: $a = 2, $b = 3, $c = 3, $d = 4, $e = 4, $f = 4
If I use this code:
$var = compact('a', 'b', 'c', 'd', 'e', 'f');
arsort($var);
$name = key($var);
The variable $name will contain only $d. The question is, how to get $d, $e, $f?
Try array_keys() with the search argument:
$var = compact('a', 'b', 'c', 'd', 'e', 'f');
arsort($var);
$max = reset($var); // get the maximum value (first item)
$results = array_keys($var, $max, true); // search for all the maximums and return the keys
Or use max() without sorting:
$var = compact('a', 'b', 'c', 'd', 'e', 'f');
$max = max($var); // get the maximum value
$results = array_keys($var, $max, true); // search for all the maximums and return the keys

Check if each values are in different arrays

I need to check if element 'a' is present twice, 'b' is present twice and 'c' is present once in a group of arrays. Each element should be in five different arrays.
That is like, 'a' in array1, another 'a' in array2, 'b' in array3, another 'b' in array4 and 'c' in array5. there should be atleast five or more arrays and each element should be in different arrays using php. Now my code is
$arr = array(
$branch1 = array('a', 'b'),
$branch2 = array('b','c'),
$branch3 = array('a', 'c'),
$branch4 = array('c', 'a'),
$branch5 = array('b', 'a'),
$branch6 = array('b', 'c', 'a')
);//This may have any number of branches and any kind of combinations of a, b and c(but each element only once in each array).
$reqd_branch_count = 5;//required branch count
As I am new to php, now I have written a very long code, but it fails when trying new combinations.Please help me if someone knows.
From asker's comment:
The condition is a user has some ranks in his/her downline which are
in branches. for example rank1, rank2 and rank3,.... Those rank counts
are shown in that array. If that user need to get rank8 he/she should
have one rank 7, two rank 5 or 7s, and two rank4s, that should be
1+2+2=5 branches, that is each rank should be in different branches.
Hope you understood the question
if i understood correctly
merge all arrays, count amount of all items in all arrays and test you want
$arr = array_merge($branch1,$branch2,$branch3,$branch4,$branch5,$branch6);
$count = array_count_values($arr);
echo $count[7]; // 4
echo $count[4]; // 2
so, yuo can make condition
if (($count[7] == 1) or ($count[7] == 2) or ($count[5] == 2) or ($count[4] == 2))
{ any stuff for true}
UPDATE
$arr = array(
$branch1=array('3'),
$branch2=array('4'),
$branch3=array('3','5','7'),
$branch4=array('3','4','7'),
$branch5=array('7'),
$branch6=array('4','7'));
// find rank per branch
$ranks = array_map('max', $arr);
// make array rank => amount
$count = array_replace(array_fill(0,7,0), array_count_values($ranks));
if (($count[7] >= 1) and (($count[7] + $count[5]) >= 2) and (($count[7] + $count[5] + $count[4]) >= 5)) {
echo "Satisfy ";
}
Because it is another question, this is another answer
$arr = array(
$branch1 = array('a'),
$branch2 = array('b','c'),
$branch3 = array('a', 'c'),
$branch4 = array('c', 'a'),
$branch5 = array('a'),
$branch6 = array( 'c', 'a')
);
$names = array('a', 'b', 'c'); // for convenience only
var_dump(goNext($arr, $names)); // watch result
function goNext($arr, $names) {
// for each name make array with list of brances where it is
$in = array(array(), array(), array());
foreach($arr as $k1 => $branch)
foreach($names as $k2 => $letter)
if(in_array($letter, $branch)) $in[$k2][] = $k1;
foreach ($in[0] as $i1) // 1st a
foreach (array_diff($in[0], array($i1)) as $i2) // 2nd a
foreach (array_diff($in[1], array($i1,$i2)) as $i3) // 1st b
foreach (array_diff($in[1], array($i1,$i2,$i3)) as $i4) // 2nd b
foreach(array_diff($in[2], array($i1,$i2,$i3,$i4)) as $i5) {
// if here we find combination we need
// next line only for debug
// it shows set of branches that give true
// a a b b c
echo $i1 . " " . $i2 . " " . $i3 . " " . $i4 . " " . $i5;
return(true);
}
return(false); // combination has not found
}

PHP Script and max() Value

Sorry for my bad English and thanks for your help in advance! I have kind of a tricky problem I've encountered while coding. Here's the point:
I need a script that essentially extracts the 5 max values of 5 arrays, that are "mixed", i.e. they contain "recurrent" values. Here is an example:
array1(a, b)
array2(a, c, d, e, g)
array3(b, d, g, h)
array4(e, t, z)
array5(b, c, d, k)
The 2 essential requests are:
1) the sum of those 5 arrays (array1+array2+array3...) MUST be the highest possible...
2) ...without repeat ANY value previously used** (e.g. if in array1 the top value was "b", this cannot be re-used as max value in arrays 3 or 5).
Currently I have this...:
$group1 = array(a, b);
$group = array(a, b, c, d);
$max1a = max(group1);
$max2a = max(group2) unset($max1a);
$sum1 = $max1a + $max2a;
$max2b = max(group2);
$max1b = max(group1)
unset($max2b);
$sum2 = $max1b + $max2b;
if($sum1 > $sum2) {
echo $sum1
} else {
echo $sum2
}
... but it's kinda impossible to use this code with 5 arrays, because I should compare 5! (120...!!!) combinations in order to find the max sum value.
I know the problem is quite difficult to explain and to solve, but I really need your help and I hope you can save me!!!
Cheers
I'm adding this as another answer to leave the previous one intact for someone coming across this looking for that variation on this behaviour.
Given the 2 arrays:
$array1 = array(30, 29, 20);
$array2 = array(30, 20, 10);
The maximum sum using one element from each is 59 - this is dramatically different to my previous approach (and the answers' of others) which took the max element of the first array and then the highest element of the next array that is not equal to any previously used value - this would give 50 instead.
The code you want is this:
$mainArray = array();
$mainArray[] = array(30, 29, 20);
$mainArray[] = array(30, 20, 10);
$tempArray = array();
$newArray = array();
foreach($mainArray as $innerArray) {
$newArray = array();
if (count($tempArray) == 0) {
foreach ($innerArray as $value) {
$newArray[] = array('total' => $value, 'used' => array($value));
}
}
else {
foreach ($tempArray as $key => $innerTempArray) {
$placed = FALSE;
foreach ($innerArray as $value) {
if (!(in_array($value, $innerTempArray['used']))) {
$newArray[] = array('total' => $tempArray[$key]['total'] + $value, 'used' => $tempArray[$key]['used']);
$newArray[count($newArray) - 1]['used'][] = $value;
$placed = TRUE;
}
}
if (!($placed)) {
echo "An array had no elements that had not already been used";
die();
}
}
}
$tempArray = $newArray;
}
$total = 0;
if (count($newArray) == 0) {
echo "No data passed";
die();
}
else {
$total = $newArray[0]['total'];
}
for ($i = 0; $i < count($newArray); $i++) {
if ($newArray[$i]['total'] > $total) {
$total = $newArray[$i]['total'];
}
}
var_dump($total);
EDIT - Do not repeat used variables (but repeated values are ok):
Let
//$a = 30, $b = 30, $c = 25, $d = 20, $e = 19
$array1 = array($a, $c, $d);
$array2 = array($b, $d, $e);
We want to choose $a from $array1 and $b from $array2 as these give the largest sum - although they're values are the same that is allowed because we only care if the names of the variables saved to that place are the same.
With the arrays in the above format there is no way of achieving the desired behaviour - the arrays do not know what the name of the variable who's value was assigned to their elements, only it's value. Therefore we must change the first part of the original answer to:
$mainArray[] = array('a', 'c', 'd');
$mainArray[] = array('b', 'd', 'e');
and also have either the of the following before the first foreach loop (to declare $a, $b, $c, $d, $e)
//either
extract(array(
'a' => 30,
'b' => 30,
'c' => 25,
'd' => 20,
'e' => 19
));
//or
$a = 30; $b = 30; $c = 25; $d = 20; $e = 19;
The above both do exactly the same thing, I just prefer the first for neatness.
Then replace the line below
$newArray[] = array('total' => $value, 'used' => array($value));
with
$newArray[] = array('total' => ${$value}, 'used' => array($value));
The change is curly brackets around the first $value because that is then evaluated to get the variable name to use (like below example):
$test = 'hello';
$var = 'test';
echo ${$var}; //prints 'hello'
A similar change replaces
$newArray[] = array('total' => $tempArray[$key]['total'] + $value, 'used' => $tempArray[$key]['used']);
with
$newArray[] = array('total' => $tempArray[$key]['total'] + ${$value}, 'used' => $tempArray[$key]['used']);
Now the code will function as wanted :)
If you are dynamically building the arrays you are comparing and can't build the array of strings instead of variables then there is no way to do it. You would need some way of extracting "$a" or "a" from $a = 30, which PHP is not meant to do (there are hacks but they are complicated and only work in certain situations (google "get variable name as string in php" to see what I mean)
If by the top value you mean the first alphabetically then the following would work:
$array1 = array('a', 'b');
$array2 = array('a', 'c', 'd', 'e', 'g');
$array3 = array('b', 'd', 'g', 'h');
$array4 = array('e', 't', 'z');
$array5 = array('b', 'c', 'd', 'k');
$mainArray = array($array1, $array2, $array3, $array4, $array5);
foreach ($mainArray as $key => $value) {
sort($mainArray[$key]);
}
$resultArray = array();
foreach($maniArray as $key1 => $value1) {
$placed = FALSE;
foreach ($value1 as $value2) {
if (!(in_array($value2, $resultArray))) {
$resultArray[] = $value2;
$placed = TRUE;
break;
}
}
if (!($placed)) {
echo "All the values in the " . ($key + 1) . "th array are already max values in other arrays";
die();
}
}
var_dump($resultArray);
I'm not sure, of i really understood your problem correctly, these are my assumptions:
You have five arrays containing numbers
These numbers can occur multiple times across the arrays
You want to find the highest possible sum of elements across your arrays
The sum uses one single value of each array
But the sum must not use the same number twice
Is that correct?
If Yes, then:
The highest possible sum across all arrays is always the sum of the largest elements. If you do not want to use the same number twice, you can just get the maximum from the first array, remove it from all the others and then sum up all the remaining maxima.
Like so:
$arrays = array();
$arrays[] = array(1, 2);
$arrays[] = array(1, 3, 4, 5, 7);
$arrays[] = array(2, 4, 7, 8);
$arrays[] = array(5, 20, 26);
$arrays[] = array(2, 3, 4, 11);
for($i=0, $n=count($arrays); $i<$n; $i++) {
if($i===0) {
$a1max = max($arrays[$i]);
$sum = $a1max;
} else {
$duplicate_pos = array_search($a1max, $arrays[$i]);
if($duplicate_pos !== FALSE) {
unset($arrays[$i][$duplicate_pos]);
}
$sum += max($arrays[$i]);
}
}
echo "sum: " . $sum . "\n";
Assuming you have grouped together all your values in one array like this,
$array = array(
array(1,2,3),
array(1,2,3,4),
array(1,2,3,4,5,6),
array(1,2,3,4,5,6),
array(1,2,3,4,5,6,7)
);
Loop through $array, and get the highest value which has not been used previously,
$max = array();
foreach($array as $value)
$max[] = max(array_diff($value, $max));
Calculate the sum of all values with array_sum(),
echo "The maximal sum is: ".array_sum($max);

php - string replacement

I am trying to do chord transposition in PHP the array of Chord values are as followed...
$chords1 = array('C','C#','D','D#','E','F','F#','G','G#','A','A#','B','C','Db','D','Eb','E','F','Gb','G','Ab','A','Bb','B','C');
An example would be D6/F#. I want to match the array value and then transpose it by a given number position in the array. Here is what I have so far...
function splitChord($chord){ // The chord comes into the function
preg_match_all("/C#|D#|F#|G#|A#|Db|Eb|Gb|Ab|Bb|C|D|E|F|G|A|B/", $chord, $notes); // match the item
$notes = $notes[0];
$newArray = array();
foreach($notes as $note){ // for each found item as a note
$note = switchNotes($note); // switch the not out
array_push($newArray, $note); // and push it into the new array
}
$chord = str_replace($notes, $newArray, $chord); // then string replace the chord with the new notes available
return($chord);
}
function switchNotes($note){
$chords1 = array('C','C#','D','D#','E','F','F#','G','G#','A','A#','B','C','Db','D','Eb','E','F','Gb','G','Ab','A','Bb','B','C');
$search = array_search($note, $chords1);////////////////Search the array position D=2 & F#=6
$note = $chords1[$search + 4];///////////////////////then make the new position add 4 = F# and A#
return($note);
}
This works, except the problem is that if I use a split chord like (D6/F#) The chord is transposed to A#6/A#. It is replacing the first note (D) with an (F#) then, Both (F#'s) with an (A#).
The question is... How can I keep this redundancy from happening. The desired output would be F#6/A#. Thank you for your help. If the solution is posted, I WILL mark it as answered.
You can use preg_replace_callback function
function transposeNoteCallback($match) {
$chords = array('C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B', 'C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B', 'C');
$pos = array_search($match[0], $chords) + 4;
if ($pos >= count($chords)) {
$pos = $pos - count($chords);
}
return $chords[$pos];
}
function transposeNote($noteStr) {
return preg_replace_callback("/C#|D#|F#|G#|A#|Db|Eb|Gb|Ab|Bb|C|D|E|F|G|A|B/", 'transposeNoteCallback', $noteStr);
}
Test
echo transposeNote("Eb6 Bb B Ab D6/F#");
returns
G6 C# Eb C F#6/A#
Cheap advice: move into natural numbers domain [[0-11]] and associate them with corresponding notes at display time only, it will save you many time.
The only problem will be homophones sounds [e.g. C-sharp / D-flat], but hope you can deduce it from tonality.

Categories