I am using asort to sort the numeric array. For e.g.
$arr = [0,1,1,2,1,2,2,3];
After running asort I am getting:
Array
(
[0] => 0
[4] => 1
[2] => 1
[1] => 1
[6] => 2
[3] => 2
[5] => 2
[7] => 3
)
But I am expecting to get it in this order:
Array
(
[0] => 0
[1] => 1
[2] => 1
[4] => 1
[3] => 2
[5] => 2
[6] => 2
[7] => 3
)
See the difference in order of the keys above.
First sort the array.
Then generate an array by flipping in a way so that the keys can be separated according to values. Sort the arrays with keys and merge them to an array. And the combine the keys with the sorted values.
$arr = [0,1,1,2,1,2,2,3];
asort($arr);
$sorted = $arr;
$flipped = $new_keys = array();
foreach($arr as $key => $val) {
$flipped[$val][] = $key; // Get the keys
}
foreach($flipped as $key => $val_array) {
asort($val_array); // Sort the keys
$new_keys = array_merge($new_keys, $val_array);
}
$final = array_combine($new_keys, $sorted); // Combine them again
var_dump($final);
Output
array(8) {
[0]=>
int(0)
[1]=>
int(1)
[2]=>
int(1)
[4]=>
int(1)
[3]=>
int(2)
[5]=>
int(2)
[6]=>
int(2)
[7]=>
int(3)
}
This should work for you:
First walk through each array value with array_walk() and change each value to an array containing the value and the key.
After this use uasort() to sort your array and if both values are the same you use the key to choose which one should be first.
At the end just use array_column() to transform your array back.
<?php
$arr = [0,1,1,2,1,2,2,3];
array_walk($arr, function(&$v, $k){
$v = ["value" => $v, "key" => $k];
});
uasort($arr, function($a, $b){
if($a["value"] == $b["value"]) {
if($a["key"] == $b["key"])
return 0;
return $a["key"] > $b["key"] ? 1 : -1;
}
return $a["value"] > $b["value"] ? 1 : -1;
});
$arr = array_column($arr, "value", "key");
print_r($arr);
?>
output:
Array
(
[0] => 0
[1] => 1
[2] => 1
[4] => 1
[3] => 2
[5] => 2
[6] => 2
[7] => 3
)
Related
Supposed I have an array of
array(8) {
[0] =>
array(1) {
'Peter' =>
int(4)
}
[1] =>
array(1) {
'Piper' =>
int(4)
}
[2] =>
array(1) {
'picked' =>
int(4)
}
[3] =>
array(1) {
'peck' =>
int(4)
}
[4] =>
array(1) {
'pickled' =>
int(4)
}
How can I sort this multidimentional array by key example (Peter). I tried using
ksort($arr);
but it just return a boolean
The output that I want
array(8) {
[0] =>
array(1) {
'peck' =>
int(4)
}
[1] =>
array(1) {
'Peter' =>
int(4)
}
[2] =>
array(1) {
'picked' =>
int(4)
}
[3] =>
array(1) {
'pickled' =>
int(4)
}
[4] =>
array(1) {
'piper' =>
int(4)
}
the array should be sorted by key and in ascending order.
Sort with usort like this, check the demo
usort($array,function($a,$b){
return strcmp(strtolower(key($a)),strtolower(key($b)));
});
The ksort() method does an in-place sort. So while it only returns a boolean (as you correctly state), it mutates the values inside $arr to be in the sorted order. Note that based on your expected output, it looks like you want to do a case insensitive search. For that, you need to use the SORT_FLAG_CASE sort flag. So, instead of calling ksort($arr), you instead want to use ksort($arr, SORT_FLAG_CASE). You can see how ksort() uses sort flags, in the sort() method's documentation. Hope that helps!
You can do something like this,
$temp = array_map(function($a){
return key($a); // fetching all the keys
}, $arr);
natcasesort($temp); // sorting values case insensitive
$result = [];
// logic of sorting by other array
foreach($temp as $v){
foreach($arr as $v1){
if($v == key($v1)){
$result[] = $v1;
break;
}
}
}
Demo
Output
Array
(
[0] => Array
(
[peck] => 4
)
[1] => Array
(
[Peter] => 4
)
[2] => Array
(
[picked] => 4
)
[3] => Array
(
[pickled] => 4
)
[4] => Array
(
[Piper] => 4
)
)
Array1 ( [0] => [1] => [2] => 3 [3] => [4] => 5 [5] => [6] => )
Array2 ( [0] => URD [1] => ISL )
I want to map $array2 values to $array1 indexes (those having values 3 and 5) and I want get an array like this:
Array ( [0] => [1] => [2] => URD [3] => [4] => ISL [5] => [6] => )
I have tried the following:
$newArray = array_values(array_filter(array_merge($array1,$array2)));
but the actual result is:
Array([0] => 3[1] => 5[2] => URD[3] => ISL)
The expected result should be:
Array ( [0] => [1] => [2] => URD [3] => [4] => ISL [5] => [6] => )
Code
Try the following:
<?php
$array1 = ["", "", "3", "", "5", "", ""];
$array2 = ["URD", "ISL"];
foreach($array1 as $id => $a1){
//for each item in array 1
if($a1){
//if the array 1 item has a value
$array1[$id] = array_shift($array2);
//replace it with an item from array 2
}
if(empty($array2)){
//if there are no more values left to share in array 2, stop
break;
}
}
var_dump($array1);
Output
array(7) {
[0]=>
string(0) ""
[1]=>
string(0) ""
[2]=>
string(3) "URD"
[3]=>
string(0) ""
[4]=>
string(3) "ISL"
[5]=>
string(0) ""
[6]=>
string(0) ""
}
Caveats
The method assumes that there will be values in both array 1 and array 2.
Once the values in array 2 have been split out and array 2 is empty, array 1 items with set values will no longer be affected.
The method does not care what the value set in array 1 is, just that there is a value.
Further reading
foreach()
array_shift()
Codepen
https://3v4l.org/RDQY6
This solution works and simple to understands as OPS requested...
<?
$array1 = ["", "", "3", "", "5", "", ""];
$array2 = ["URD", "ISL"];
$i =0;
foreach($array1 as $keys=>$values) {
if($values == 3 || $values ==5) {
if(isset($array2[$i])){
$array1[$keys] = $array2[$i];
$i++;
}else { break; }
}
}
print_R($array1);
?>
it will replace the array2 values from array 1 values wherever 5 & 3 will come and which is independent of their sorting order.
example
$array1 = ["5", "", "3", "", "", "", ""]; will be converted into
$array1 = ["URD", "" ,"ISL","","",""];
if you want it in order like 3 should always come first then first sort array1 then use my code...
if you want 3 should be replace by URD and 5 should be replace by ISL
then you if codition will be different
Just another way to do it... (untested, but it should work)
<?php
$a = array ( 0 => '', 1 => '', 2 => 3, 3 => '', 4 => 5, 5 => '', 6 => '' );
$b = array ( 0 => 'URD', 1 => 'ISL' );
$c = array_replace ( $a, array_combine ( array_keys ( array_filter ( $a ) ), $b ) );
print_r ( $c );
?>
Basically, I want to convert the below multidimensional array:
Array
(
[0] => Array
(
[0] => foo
[1] => bar
[2] => hello
)
[1] => Array
(
[0] => world
[1] => love
)
[2] => Array
(
[0] => stack
[1] => overflow
[2] => yep
[3] => man
)
)
Into this:
Array
(
[0] => foo
[1] => world
[2] => stack
[3] => bar
[4] => love
[5] => overflow
[6] => hello
[7] => yep
[8] => man
)
first element from first sub-array
first element from second sub-array, etc
second element from first sub-array
second element from second sub-array, etc...
So I've had a couple beers and I'll try and tighten this up later, but this does the trick for integer indexed arrays:
$result = array();
for($i=0; $c=array_column($array, $i); $i++) {
$result = array_merge($result, $c);
}
print_r($result);
Loop getting an array of columns starting with column 0 and increment the column number.
So long as there are columns, get an array of that column and merge with the result.
There is an often overlooked Iterator that will help you here: The MultipleIterator.
I have created some demo code: https://3v4l.org/beOMV
<?php
$arr = [
0 => [
0 => 'foo',
1 => 'bar',
2 => 'hello',
],
1 => [
0 => 'world',
1 => 'love',
],
2 => [
0 => 'stack',
1 => 'overflow',
2 => 'yep',
3 => 'man',
]
];
$parallelIterator = new MultipleIterator(MultipleIterator::MIT_NEED_ANY|MultipleIterator::MIT_KEYS_NUMERIC);
$parallelIterator->attachIterator(new ArrayIterator($arr[0]));
$parallelIterator->attachIterator(new ArrayIterator($arr[1]));
$parallelIterator->attachIterator(new ArrayIterator($arr[2]));
$result = [];
foreach ($parallelIterator as $values) {
foreach ($values as $value) {
if ($value !== null) {
$result[] = $value;
}
}
}
var_dump($result);
Essentially, iterating over the MultipleIterator will give you an array with all the first entries (and then second and so on) of ALL attached iterators in parallel. By using either MultipleIterator::MIT_NEED_ANY or MultipleIterator::MIT_NEED_ALL you can decide that the loop should stop either when the last iterator has no more elements, or when the first iterator runs out of elements. When you run until the last element of the last iterator, you'll get NULL instead.
When attaching iterators, you can also add a key that will be used in the array when iterating, and have to uses MultipleIterator::MIT_KEYS_ASSOC - I have simply used numeric indices here because the source of the particular array was not interesting.
The result is
array(9) {
[0]=> string(3) "foo"
[1]=> string(5) "world"
[2]=> string(5) "stack"
[3]=> string(3) "bar"
[4]=> string(4) "love"
[5]=> string(8) "overflow"
[6]=> string(5) "hello"
[7]=> string(3) "yep"
[8]=> string(3) "man"
}
Yes, you can iterate over that initial array when attaching the sub arrays to the MultipleIterator if you want:
foreach ($arr as $innerArr) {
$parallelIterator->attachIterator(new ArrayIterator($innerArr));
}
This is pretty basic, but my question is:
Given an array:
$a = array(
0 => array('Rate'=> array('type_id'=>1, 'name' => 'Rate_1', 'type'=>'day','value'=>10)),
1 => array('Rate'=> array('type_id'=>1, 'name' => 'Rate_2', 'type'=>'night','value'=>8)),
2 => array('Rate'=> array('type_id'=>2, 'name' => 'Rate_3', 'type'=>'day','value'=>7)),
3 => array('Rate'=> array('type_id'=>2, 'name' => 'Rate_4', 'type'=>'nigh','value'=>16)),
4 => array('Rate'=> array('type_id'=>3, 'name' => 'Rate_5', 'type'=>'day','value'=>10))
);
What is the most efficient way to change it so we have something like:
$new_array = array(
[type_id] => array(
[type] => array(
[value]
)
)
)
);
In other words, I would like to strip some data (the name, which I don't need) and reorganise the dimensions of the array. In the end I would have an array which I would be able to access the values by $new_array['type_id']['type']['value'].
Not entirely sure if this is exactly what you want, but with this you can access the values by saying
echo $new[TYPE_ID][DAY_OR_NIGHT];
$new = array();
foreach($a AS $b){
$c = $b['Rate'];
$new[$c['type_id']][$c['type']] = $c['value'];
}
Using print_r on $new would give you:
Array
(
[1] => Array
(
[day] => 10
[night] => 8
)
[2] => Array
(
[day] => 7
[night] => 16
)
[3] => Array
(
[day] => 10
)
)
Since php 5.3.0, array_reduce() allows using an array as the initial value, given your initial array $a, you can use the following code
function my_reducer ($result, $item) {
$result[$item['Rate']['type_id']][$item['Rate']['type']] = $item['Rate']['value'];
return $result;
}
$assoc_arr = array_reduce($a, 'my_reducer', array());
var_dump($assoc_arr);
This returns
array(3) { [1]=> array(2) {
["day"]=>
int(10)
["night"]=>
int(8) } [2]=> array(2) {
["day"]=>
int(7)
["nigh"]=>
int(16) } [3]=> array(1) {
["day"]=>
int(10) } }
I have an array:
Array
(
[0] => 0
[1] => 1
[2] => 2
[3] => 3
[4] => 4
[5] => 5
[6] => 6
[7] => 7
[8] => 8
[9] => 9
)
I want to split the array into alternating chunks. (size 2 then 3 then 2 then 3 etc)
Array
(
[0] => Array
(
[0] => 0
[1] => 1
[2] => 2
)
[1] => Array
(
[0] => 3
[1] => 4
)
[2] => Array
(
[0] => 5
[1] => 6
[2] => 7
)
[3] => Array
(
[0] => 8
[1] => 9
)
)
That should work:
$a = array(0 => 0,1 => 1,2 => 2,3 => 3,4 => 4, 5 => 5, 6 => 6,7 => 7,8 => 8,9 => 9);
$chunks = array();
$i=1;
while(count($a)){
$chunks[] = array_splice($a, 0,(2+($i%2)),array());
$i++;
}
echo "<pre>";
var_dump($chunks);
You can use array_splice for splitting the array, but you need to set conditions right? On what basis do you wanna split them?
And you can use array_merge to bring them back into an array of arrays.
In case of your current code, the code will be:
PHP Code
<?php
$array = array(0,1,2,3,4,5,6,7,8,9);
$final = array(
array_splice($array, 0, 3),
array_splice($array, 1, 2),
array_splice($array, 1, 2),
array_splice($array, 1, 2),
);
print_r($final);
?>
Output
Array
(
[0] => Array
(
[0] => 0
[1] => 1
[2] => 2
)
[1] => Array
(
[0] => 4
[1] => 5
)
[2] => Array
(
[0] => 6
[1] => 7
)
[3] => Array
(
[0] => 8
[1] => 9
)
)
Fiddle here: http://codepad.org/JzxcZ2Q1
Iterated calls of array_splice() seems like a great way to go. Here is a cleaner version of István Őri's answer. Subtracting from 5 removes the need to use the modulus operator.
Code: (Demo)
$array = range(1, 10);
$chunks = [];
$chunkSize = 3;
while ($array) {
$chunkSize = 5 - $chunkSize;
$chunks[] = array_splice($array, 0, $chunkSize);
}
var_export($chunks);
This snippet modifies $array as it iterates. array_splice() keeps removing elements from the front of the array. Eventually the array will become empty and the while() condition will fail -- breaking the loop.
You could use this, it isn't the most elegant, but it will just do the trick for you - and you can modify it nicely and adapt it to suit your purposes further:
<?php
$originalArray = array(0,1,2,3,4,5,6,7,8,9);
$counter=count($originalArray);
$isTwo=true;
$newArray=array();
$arrElement=0;
$i=0;
while($i<$counter)
{
if($isTwo)
{
$newArray[$arrElement]= array();
for($j=0; $j<2; $j++)
{
$newArray[$arrElement][$j]=$originalArray[$i+$j];
}
$i+=2;
$isTwo=false;
$arrElement++;
}
else
{
$newArray[$arrElement]= array();
for($j=0; $j<3; $j++)
{
$newArray[$arrElement][$j]=$originalArray[$i+$j];
}
$i+=3;
$isTwo=true;
$arrElement++;
}
}
var_dump($newArray);
?>
Output:
array(4) {
[0]=>
array(2) {
[0]=>
int(0)
[1]=>
int(1)
}
[1]=>
array(3) {
[0]=>
int(2)
[1]=>
int(3)
[2]=>
int(4)
}
[2]=>
array(2) {
[0]=>
int(5)
[1]=>
int(6)
}
[3]=>
array(3) {
[0]=>
int(7)
[1]=>
int(8)
[2]=>
int(9)
}
}
$tobechunked_arr = array(0,1,2,3,4,5,6,7,8,9);
$chunk_size_arr = array(3,2,3,2);
$j = 0;
foreach($chunk_size_arr as $key => $val)
{
for($i = 0; $i < $val; $i++)
{
$result_arr[$key][] = $tobechunked_arr[$j];
$j++;
}
}
echo "<pre>";
print_r($result_arr);
try this
<?php
$input_array = array('a', 'b', 'c', 'd', 'e');
print_r(array_chunk($input_array, 2));
print_r(array_chunk($input_array, 2, true));
?>
Update
<?php
$myArray = array("abc","def","ghi","jkl","mno","pqr","stu","vwx","yz");
$newArray = array_chunk($myArray, 2, false);
// Now process the multidimensional array made from array_chunk()
$i = 0;
foreach ($newArray as $inner_array) {
$i++;
echo "<h2>Chunk $i</h2>";
while (list($key, $value) = each($inner_array)) {
echo "$key: $value <br />";
}
}
?>
Output
Chunk 1
0: abc
1: def
Chunk 2
0: ghi
1: jkl
Chunk 3
0: mno
1: pqr
Chunk 4
0: stu
1: vwx
Chunk 5
0: yz