How to combine strings $a and $b so that 1st digit of $a is placed as 2nd character of $b, 2nd digit as 4th character of $b, 3rd digit as 7th character of $b and 4th digit as 11th character of $b.
So lets say $a = 1234
and $b = abcdefghijklmnop
I want to get this: a1b2cd3efg4hijklmnop
Is there a function to combine it like this + reverse back if needed?
You could do this using multiple array and using array_splice() to insert the value at a certain point.
$logicArr = [1,3,6,10]; //Logic Array = Each position of array
$arrOne = [1,2,3,4]; //Values to add to the array
$arrTwo = ['a','b','c','d','e','f','g', 'h','i','j','k','l','m','n','o','p']; //Data Array
foreach ($arrOne as $k=>$v) {
array_splice($arrTwo, $logicArr[$k], 0, $v); //Insert value from $arrOne at position $logicArr[$k] using iteration of Foreach loop.
}
You could iterate through each character in $b and only insert the next character from $a whenever you reach the desired position:
function mix($a, $b)
{
$a = str_split($a);
$b = str_split($b);
$mixed = '';
$nextInsertPos = 1; // 2nd character
$indexA = 0;
foreach ($b as $indexB => $charB) {
if ($indexB + $indexA == $nextInsertPos) {
$mixed .= $a[$indexA++];
$nextInsertPos = $nextInsertPos + ($indexA + 1);
}
$mixed .= $charB;
}
return $mixed;
}
Related
I want to get the sum of all selected values from an array. If a user searches for a word it should return a sum for the searched word. Example below.
$chars = array(1 => 'a', 2 => 'b', 3 => 'c'); // Chars start from a-z
$data = 'aac'; // for example
foreach ($chars as $results) {
if (strpos($results, $data) !== false) {
$search = array_search($results, $chars);
}
}
If search is "aac" then the results should be 1 + 1 + 3 = 5.
I have tried the array_keys() function and it did not work.
You can split your $data into an array and loop over every character in the string. Search for the string in the array, and if it exists, then add the index you get from array_search() to a $sum variable.
$sum = 0;
foreach (str_split($data) as $char) {
if (($index = array_search($char, $chars)) !== false) {
$sum += $index;
}
}
echo $sum;
Live demo at https://3v4l.org/XCK8r
You can use str_split to create a character array, then accumulate lowercase alphabetical characters only into a sum. Use ord to get an ASCII code per letter instead of hardcoding a literal array (the array would only be useful if you want arbitrary weights per character; see other answers).
<?php
$data = "aac";
$result = array_reduce(str_split($data), function ($a, $e) {
return $a + (ctype_lower($e) ? ord($e) - 96 : 0);
}, 0);
echo $result; // => 5
If you wish to ignore case and treat "A" as "a", you can use strtolower.
<?php
$data = "aAc";
$result = array_reduce(str_split(strtolower($data)), function ($a, $e) {
return $a + (ctype_lower($e) ? ord($e) - 96 : 0);
}, 0);
echo $result; // => 5
To save having to search the array for the value of the character, instead use array_flip() to make it an array indexed by the character itself. Then just add the items up (using ?? in case the item doesn't exist to add 0)...
$sum = 0;
$chars = array_flip($chars);
foreach (str_split($data) as $char) {
$sum += $chars[$char] ?? 0;
}
echo $sum;
For example, input array is [9,1,9,1,3,9,1,2,9] output array will be [9,9,9,9,1,1,1,2,3].
Here's what I've tried below but not giving me expected result:
$array = [9,1,9,1,3,9,1,2,9];
$values = array_count_values($array);
arsort($values);
$popular = array_keys($values);
print_r(array_values($popular));
foreach ($values as $key => $val) {
echo $key.", ";
}
Output:
Array
(
[0] => 9
[1] => 1
[2] => 3
[3] => 2
)
9, 1, 3, 2,
If we loop the array_count_values then we can make sure they come in the correct order.
When there is two that is the same count I find all the same with array_intersect then foreach them and add in the correct order.
$array = [9,1,9,1,3,9,1,2,9];
$values = array_count_values($array);
arsort($values);
//var_dump($values);
$result =[];
$same = [];
foreach($values as $key => $val){
if(!in_array($key, array_keys($same))){
if(next($values) != $val){
$result = array_merge($result, array_fill(0, $val, $key));
}else{
$same = array_intersect($values, [$val]);
ksort($same);
foreach($same as $skey => $val){
$result = array_merge($result, array_fill(0, $val, $skey));
}
//var_dump($same);
}
}
}
var_dump($result);
https://3v4l.org/sk44Q
Try usort combined with array_count (php >= 7.0):
$array = [9,1,9,1,3,9,1,2,9];
$arrayCounts = array_count_values($array);
usort($array, function ($a, $b) use ($arrayCounts) {
$countA = $arrayCounts[$a] ?? 0;
$countB = $arrayCounts[$b] ?? 0;
if ($countA == $countB) {
return $a == $b ? 0 : ($a < $b ? -1 : 1);
}
return ($countA > $countB) ? -1 : 1;
});
You could use this sequence:
$arrayCounts = array_count_values($array);
usort($array, function ($a, $b) use ($arrayCounts) {
return $arrayCounts[$b] - $arrayCounts[$a] ?: $a - $b;
});
Now $array is sorted as requested.
The callback function that is passed as argument to usort should return a negative number when the two elements $a and $b should stay in that order (from left to right), or a positive number when they should be reversed. 0 when it does not matter.
The numeric expression that is returned in this particular callback function subtracts the frequencies of $a and $b. If $b occurs more, then that subtraction is positive, and that is returned. Similarly if the subtraction is negative, then that negative value is returned. Now when the frequencies are equal, the ?: operator kicks in and the expression after it is evaluated. That other subtraction also results in a positive or negative value, based on the original value itself. So $a - $b will be negative when $a < $b, which means the order can remain as it is (knowing that we already derived that their frequencies were equal).
I'm trying to customise PHP's usort function to change the character sort order.
At present, only the "*" symbol character equates to having a value less than letter characters, e.g. "a", i.e. "*" < "a" = TRUE. Other symbols, such as "{", have values greater than letters, e.g. "a", i.e. "{" < "a" = FALSE.
I would like to sort so the value "{*}" is at the top of the sorted array, as if the value was "*". Here's the function I'm currently using, to sort an array of objects by multiple properties of the objects. [Attribution: It's a modified version of Will Shaver's code on the usort docs.]
function osort($array, $properties) {
//Cast to an array and specify ascending order for the sort if the properties aren't already
if (!is_array($properties)) $properties = [$properties => true];
//Run the usort, using an anonymous function / closures
usort($array, function($a, $b) use ($properties) {
//Loop through each specified object property to sort by
foreach ($properties as $property => $ascending) {
//If they are the same, continue to the next property
if ($a -> $property != $b -> $property) {
//Ascending order search for match
if ($ascending) {
//if a's property is greater than b, return 1, otherwise -1
return $a -> $property > $b -> $property ? 1 : -1;
}
//Descending order search for match
else {
//if b's property is greater than a's, return 1, otherwise -1
return $b -> $property > $a -> $property ? 1 : -1;
}
}
}
//Default return value (no match found)
return -1;
});
//Return the sorted array
return $array;
}
What about a usort that prioritizes some characters in the order you define, and subsequently uses regular strcmp?
Something like this:
<?php
$list = [ 'abc',
'{a}',
'*',
'{*}',
'{abc',
'}a',
]; // An array of strings to sort
$customOrderPrioritized = ['{','*','}']; // Add any characters here to prioritize them, in the order they appear in this array
function ustrcmp($a, $b, $customOrderPrioritized) {
if ($a === $b) return -1; // same, doesn't matter who goes first
$n = min(strlen($a), strlen($b)); // compare up to the length of the shortest string
for ($i = 0; $i < $n; $i++) {
if ($a[$i] === $b[$i]) continue; // matching character, continue to compare next
$a_prio = in_array($a[$i], $customOrderPrioritized);
$b_prio = in_array($b[$i], $customOrderPrioritized);
// If either one has a prioritized char...
if ($a_prio || $b_prio) {
if ($a_prio && $b_prio) {
// Both are prioritized, check which one is first...
return array_search($a[$i], $customOrderPrioritized) <= array_search($b[$i], $customOrderPrioritized) ? -1 : 1;
} elseif ($a_prio) {
return -1; // a < b
} else { // must be $b_prio
return +1; // b > a
}
}
return strcmp($a[i], $b[$i]); // compare single character
}
// if they have identical beginning, shortest should be first
return strlen($a) <= strlen($b) ? -1 : +1;
}
usort(
$list,
function($a, $b) use ($customOrderPrioritized){
return ustrcmp($a, $b, $customOrderPrioritized);
}
); // run custom comparison function, pass in $customOrderPrioritized (or make it global)
print_r($list); // print the list
/* The sorted array should look like:
Array
(
[0] => {*}
[1] => {a}
[2] => {abc
[3] => *
[4] => }a
[5] => abc
)
*/
I have :
$a = array(
0=>'you',
1=>'will',
2=>'be',
3=>'so',
4=>'happy',
5=>'in'
);
$b = array(
0=>'1',
1=>'4',
2=>'5'
); // (KEYS:1,4,5)
I want out the values of $a that matches $b's keys;
so $val would be willhappyin.
And then comma-separate them.. like: will,happy,in without comma after last one.
How can i do this ? :)
$string = implode(",", array_intersect_key($a, array_flip($b)));
EXPLANATION:
array_flip switches the values of $b to keys.
array_intersect_key takes only the entries in $a that are also present in $b.
implode joins the resulting array values together by comma.
$c = array();
foreach($b as $key)
{
$c[] = $a[$key]
}
echo implode(",",$c);
$out_arr = array();
foreach ($b as $k => $v) {
array_push($out_arr, $a[$v]);
}
return join($out_arr, ',');
I need to add the values of an associative array to another one.
$a = array(4=>2,5=>5);
$b = arrray(array(0=>0,1=>4,2=>10,3=>1000),array()...);
What I'm expecting to get is a third array ($c) like the one below where the content of $b follows the content of $a:
$c = array(array(4=>2,5=>5,0=>0,1=>4,2=>10,3=>1000),array(4=>2,5=>5....));
This is what I've written (not working):
$c = array();
foreach ($possible_opp_action as $sub) {
$c[] = array_push($to_merge,array_values($sub));
}
$a = array(4=>2,5=>5);
$b = array(array(0=>0,1=>4,2=>10,3=>1000),
array(0=>0,1=>40,2=>100,3=>2000),
array(4=>10)
);
$c = array();
foreach($b as $tmp) {
$c[] = $a+$tmp;
}
var_dump($c);
Unlike array_merge, this will maintain numeric keys... but watch out for duplicate keys
$c = array();
foreach ($b as $bb) {
$c[] = array_merge($a,$bb);
}
If you do not need $b in original form:
<?php
$a = array(4=>2,5=>5);
$b = array(array(0=>0,1=>4,2=>10,3=>1000),array());
foreach ($b as &$ref) {
$ref = $a + $ref;
}
var_dump($b);
Otherwise:
<?php
$a = array(4=>2,5=>5);
$b = array(array(0=>0,1=>4,2=>10,3=>1000),array());
$c = array();
foreach ($b as &$ref) {
$c[] = $a + $ref;
}
var_dump($c);
You need array_merge.
http://us.php.net/manual/en/function.array-merge.php
Note the handling of duplicate keys:
Merges the elements of one or more arrays together so that the values of one are appended to the end of the previous one. It returns the resulting array.
If the input arrays have the same string keys, then the later value for that key will overwrite the previous one. If, however, the arrays contain numeric keys, the later value will not overwrite the original value, but will be appended.
Values in the input array with numeric keys will be renumbered with incrementing keys starting from zero in the result array.
EDIT:
I may have not read the question right - please clarify...
Do you want all the array items in a single array, or an array with the original arrays as items in it (an array of arrays)?
IE:
c = array(a=a, b=b, c=c, etc.) <- can be done with array_merge($a, $b, $c, etc)
vs
c = array(
b = array(a=a, b=b, c=c, etc),
a=array(d=d, e=e, etc.)
) <- should be done by just concatenating the next array on the end like this (and skip the $c altogether):
$c[] = $b;
$c[] = $a;
//or
$c = array();
foreach ($possible_opp_action as $sub) {
$c[] = $sub;
}
try
$c = array_merge($b, $a)
help in http://php.net/manual/es/function.array-merge.php