Find the concentration areas of one's in a unitary matrix - php

I've got some array of 0-1 elements like:
array('0,0'=>0,'1,0'=>0,'2,0'=>0,'3,0'=>1,'0,1'=>1,'1,1'=>1,'2,1'=>0,'3,1'=>0,'0,2'=>1,'1,2'=>1,'2,2'=>1,'3,2'=>1);
It looks like:
0 0 0 1
1 1 0 0
1 1 1 1
How to find all islands of 1?
In this case i would like to return values:
$island[] = array('3,0');
$island[] = array('0,1','1,1','0,2','1,2','2,2','3,2');
Of course in real cases are more expanded.
Thanks in advance.

$islands = [
[0, 0, 0, 1],
[1, 1, 0, 0],
[1, 1, 1, 1],
];
$result = [];
array_walk_recursive(
$islands,
function ($value, $key) use (&$result) {
static $c = PHP_INT_MAX;
static $r = -1;
if ($c >= $key) {
++$r;
$c = $key;
}
if ($value)
$result[] = $key . ',' . $r;
}
);
var_dump($result);

You can use a foreach inside another foreach to trawl the arrays for values of 1 like this:
<?php
$array=array(
array(0,0,0,1),
array(1,1,0,0),
array(1,1,1,1)
);
$island=array();
foreach($array as $x=>$arr)
{
foreach($arr as $y=>$val)
{
if($val==1)
{
$island[]=array($x, $y);
}
}
}
print_r($island);
?>
with the output:
Array
(
[0] => Array
(
[0] => 0
[1] => 3
)
[1] => Array
(
[0] => 1
[1] => 0
)
[2] => Array
(
[0] => 1
[1] => 1
)
[3] => Array
(
[0] => 2
[1] => 0
)
[4] => Array
(
[0] => 2
[1] => 1
)
[5] => Array
(
[0] => 2
[1] => 2
)
[6] => Array
(
[0] => 2
[1] => 3
)
)
This output finds all indexes of 1 and returns them as a a single entry in the array.
You can also use:
<?php
$array=array(
array(0,0,0,1),
array(1,1,0,0),
array(1,1,1,1)
);
$island=array();
$temp=array();
foreach($array as $x=>$arr)
{
foreach($arr as $y=>$val)
{
if($val==1)
{
$temp[]="'".$x.','.$y."'";
}
}
if(count($temp)>0)
{
$island[]=implode(',',$temp);
}
$temp=array();
}
print_r($island);
?>
Which will make an array closer to your required output:
Array
(
[0] => '0,3'
[1] => '1,0','1,1'
[2] => '2,0','2,1','2,2','2,3'
)

Related

Count consecutive repeated elements in array in the same sequence as they are

I need to count consecutive repeated elements in the array, but if they are non consecutive I want to count them also, to have them in the same sequence as they are.
For example I have flowing array:
$array = Array('a', 'b', 'a', 'a', 'a', 'c', 'c', 'b', 'b', 'a', 'a', 'a', 'a');
if I use array_count_values function
example:
print_r(array_count_values($array));
Output will be:
Array ( [a] => 8 [b] => 3 [c] => 2 )
But I need to get output like this:
element counted value
a 1
b 1
a 3
c 2
b 2
a 4
You can iterate over the array, counting values while they are the same, and pushing a value to the result array when they are different:
$result = [];
$count = 0;
$current = $array[0];
for ($i = 0; $i < count($array); $i++) {
if ($array[$i] == $current) {
$count++;
}
else {
$result[] = array($current, $count);
$count = 1;
}
$current = $array[$i];
}
$result[] = array($current, $count);
print_r($result);
Output:
Array
(
[0] => Array
(
[0] => a
[1] => 1
)
[1] => Array
(
[0] => b
[1] => 1
)
[2] => Array
(
[0] => a
[1] => 3
)
[3] => Array
(
[0] => c
[1] => 2
)
[4] => Array
(
[0] => b
[1] => 2
)
[5] => Array
(
[0] => a
[1] => 4
)
)
Demo on 3v4l.org
Starting with an array with the first item from the source (and a count of 1), this then starts from the second item and checks if it matches the one in the current output. Adding 1 if it matches or adding a new entry if it doesn't...
$array = Array ('a','b','a','a','a','c','c','b','b','a','a','a','a');
$output = [ ["element" => $array[0], "count" => 1 ] ];
$outputPoint = 0;
for ( $i = 1, $count = count($array); $i < $count; $i++ ) {
if ( $array[$i] == $output[$outputPoint]["element"] ) {
$output[$outputPoint]["count"]++;
}
else {
$output[++$outputPoint] = ["element" => $array[$i], "count" => 1 ];
}
}
print_r($output);
Which outputs...
Array
(
[0] => Array
(
[element] => a
[count] => 1
)
[1] => Array
(
[element] => b
[count] => 1
)
[2] => Array
(
[element] => a
[count] => 3
)
[3] => Array
(
[element] => c
[count] => 2
)
[4] => Array
(
[element] => b
[count] => 2
)
[5] => Array
(
[element] => a
[count] => 4
)
)
This loops through the array and increments the number of elements in $count.
$array = ['a','b','a','a','a','c','c','b','b','a','a','a','a'];
$count = [];
$crt = -1;
foreach($array ?? [] as $element) {
if($crt == -1 || $count[$crt]["element"] != $element) {
$count[++$crt] = ["element" => $element, "counted_value" => 1];
} else {
$count[$crt]["counted_value"]++;
}
}
The array looks like:
Array
(
[0] => Array
(
[element] => a
[counted_value] => 1
)
[1] => Array
(
[element] => b
[counted_value] => 1
)
[2] => Array
(
[element] => a
[counted_value] => 3
)
[3] => Array
(
[element] => c
[counted_value] => 2
)
[4] => Array
(
[element] => b
[counted_value] => 2
)
[5] => Array
(
[element] => a
[counted_value] => 4
)
)
Compare 2 elements by iterating the array, if both the elements are the same, increase the count else keep the count as 1
$index = 0;
$finalArr[$index] = array('ele'=>$array[0],'cnt'=>1);
for($i=1; $i<count($array); $i++)
{
if($array[$i]===$array[$i-1])
{
++$finalArr[$index]['cnt'];
}
else
{
$finalArr[++$index] = array('ele'=>$array[$i],'cnt'=>1);
}
}
print_r($finalArr);

Merge values from different arrays to one with the same key [duplicate]

This question already has answers here:
Transposing multidimensional arrays in PHP
(12 answers)
Closed 10 months ago.
I have two arrays:
Array
(
[0] => 5
[1] => 4
)
Array
(
[0] => BMW
[1] => Ferrari
)
And I would like to have that result. Merge the values with the same key
Array
(
[0] => Array
(
[0] => 5
[1] => BMW
)
[1] => Array
(
[0] => 4
[1] => Ferrari
)
)
How could I do that? Is there any native PHP function that does this? I tried array_merge_recursive and array_merge but did not get the expected result
As to #splash58 comment:
You can use array-map. Here an example:
$array = [["5", "4"], ["BMW", "Ferrari"]];
$res = array_map(null, ...$array);
Now res will contain:
Array
(
[0] => Array
(
[0] => 5
[1] => BMW
)
[1] => Array
(
[0] => 4
[1] => Ferrari
)
)
If the array in 2 different var you can use:
$res= array_map(null, ["5", "4"], ["BMW", "Ferrari"]);
<?php
$a = array();
$a[0] = '5';
$a[1] = '4';
$b = array();
$b[0] = 'BMW';
$b[1] = 'Ferrari';
merge_by_key($a, $b);
function merge_by_key($a, $b){
$c = array();
fill_array($c,$a);
fill_array($c,$b);
print_r($c);
}
function fill_array(&$c, $a) {
foreach ($a as $key => $value){
if(isset($c[$key])) {
array_push($c[$key], $value);
} else {
$c[$key] = array($value);
}
}
}
Output:
Array
(
[0] => Array
(
[0] => 5
[1] => BMW
)
[1] => Array
(
[0] => 4
[1] => Ferrari
)
)
You can use array_map with null as the first argument (there is an example in the manual), to get your desired result:
<?php
$nums = [0 => 5, 1 => 4];
$cars = [0 => 'BMW', 1 => 'Ferrari'];
var_export(array_map(null, $nums, $cars));
Output:
array (
0 =>
array (
0 => 5,
1 => 'BMW',
),
1 =>
array (
0 => 4,
1 => 'Ferrari',
),
)
Note that the following input would give the same result:
$nums = ['puff' => 5, 'powder' => 4];
$cars = ['powder' => 'BMW', 'puff' => 'Ferrari'];
It is the order, not the keys, that determine the pairings in the result when using array_map as above.
To associate by key using foreach (note order of $cars):
<?php
$nums = [0 => 5, 1 => 4];
$cars = [1 => 'Ferrari', 0 => 'BMW'];
foreach($nums as $k => $num)
$result[] = [$num, $cars[$k]];
var_export($result);
Results also in the desired output.

Merge multi-dimensional arrays by relating first columns and summing two other columns

I want to combine two multidimensional arrays in PHP.
print_r($array_a):
Array
(
[0] => Array
(
[0] => A
[1] => 0
[2] => 1047
)
[1] => Array
(
[0] => B
[1] => 0
[2] => 279
)
[2] => Array
(
[0] => C
[1] => 0
[2] => 68
)
[3] => Array
(
[0] => D
[1] => 0
[2] => 4
)
)
print_r($array_b):
Array
(
[0] => Array
(
[0] => A
[1] => 76
[2] => 0
)
[1] => Array
(
[0] => B
[1] => 170
[2] => 0
)
[2] => Array
(
[0] => C
[1] => 15
[2] => 0
)
[3] => Array
(
[0] => D
[1] => 210
[2] => 0
)
[4] => Array
(
[0] => E
[1] => 287
[2] => 0
)
)
Then merge it, the result should be like this:
Array
(
[0] => Array
(
[0] => A
[1] => 76
[2] => 1047
)
[1] => Array
(
[0] => B
[1] => 170
[2] => 279
)
[2] => Array
(
[0] => C
[1] => 15
[2] => 68
)
[3] => Array
(
[0] => D
[1] => 210
[2] => 4
)
[4] => Array
(
[0] => E
[1] => 287
[2] => 0
)
)
So the logic key is to merge the two array based on the first value of each array(A, B, C, D). And if there's an array that belong only in one of the array (for example, "E" on the array_b), I just add them.
I tried this:
foreach($array_a as $a=>$array_now){
foreach($array_b as $b=>$array_before){
if($array_now[0] == $array_before[0]){
$array_a[$a] = [$array_before[0], $array_before[1], $array_now[2]];
}
}
}
But I can't seem to add the missing array (the 5th array in $array_b which contain 'E').
use below code that will help you
$array_a = [];
$array_a[0][0] = 'A';
$array_a[0][1] = 0;
$array_a[0][2] = 1047;
$array_a[1][0] = 'B';
$array_a[1][1] = 0;
$array_a[1][2] = 279;
$array_a[2][0] = 'C';
$array_a[2][1] = 0;
$array_a[2][2] = 68;
$array_a[3][0] = 'D';
$array_a[3][1] = 0;
$array_a[3][2] = 4;
$array_b = [];
$array_b[0][0] = 'A';
$array_b[0][1] = 76;
$array_b[0][2] = 0;
$array_b[1][0] = 'B';
$array_b[1][1] = 70;
$array_b[1][2] = 0;
$array_b[2][0] = 'C';
$array_b[2][1] = 15;
$array_b[2][2] = 0;
$array_b[3][0] = 'D';
$array_b[3][1] = 210;
$array_b[3][2] = 0;
$array_b[3][0] = 'E';
$array_b[3][1] = 287;
$array_b[3][2] = 0;
$array_b[4][0] = 'E';
$array_b[4][1] = 2870;
$array_b[4][2] = 0;
$cnt = 0;
if(count($array_b) > $array_a){
$cnt = count($array_b);
}else{
$cnt = count($array_a);
}
$array_new = [];
for($i=0; $i <= $cnt; $i++){
$array_new[$i] = [];
if(isset($array_a[$i][0])){
$array_new[$i][0] = $array_a[$i][0];
}else{
$array_new[$i][0] = $array_b[$i][0];
}
if(isset($array_b[$i][1])){
$array_new[$i][1] = $array_b[$i][1];
}else{
$array_new[$i][1] = 0;
}
if(isset($array_a[$i][2])){
$array_new[$i][2] = $array_a[$i][2];
}else{
$array_new[$i][2] = 0;
}
}
echo "<pre>";
print_r($array_new);
Hope this will help!
You could use multiple array_maps to achieve this
$c = array_map(function() {
return array_map(function() {
foreach (func_get_args() as $arg) {
if ($arg) return $arg;
}
return func_get_arg(0);
}, ...func_get_args());
}, $a, $b);
this code would also work with more than $a, $b - just add as much arrays as you want as param
Sorry but all the above solution doesn't work, and I figured it by myself, by using this code:
$result = array();
if (count($array_a) > count($array_b)){
foreach($array_a as $a=>$array_now){
foreach($array_b as $b=>$array_before){
if($array_now[0] == $array_before[0]){
$array_a[$a] = [(string)$array_before[0], (int)$array_before[1], (int)$array_now[2]];
}
}
}
$result = $array_a;
} else {
foreach($array_b as $a=>$array_now){
foreach($array_a as $b=>$array_before){
if($array_now[0] == $array_before[0]){
$array_b[$a] = [(string)$array_before[0], (int)$array_now[1], (int)$array_before[2]];
}
}
}
$result = $array_b;
}
Thank you guys for all of your response.
This task can be concisely, efficiently, and reliably performed with a single loop which generates a result array with temporary key to determine whether a new row is encountered or not.
Code: (Demo)
$array_a = [
['A', 0, 1047],
['B', 0, 279],
['C', 0, 68],
['D', 0, 4],
];
$array_b = [
['A', 76, 0],
['B', 170, 0],
['E', 287, 0],
['C', 15, 0],
['D', 210, 0],
];
foreach (array_merge($array_a, $array_b) as $row) {
if (!isset($result[$row[0]])) {
$result[$row[0]] = $row;
} else {
$result[$row[0]][1] += $row[1];
$result[$row[0]][2] += $row[2];
}
}
var_export(array_values($result));
Output:
array (
0 =>
array (
0 => 'A',
1 => 76,
2 => 1047,
),
1 =>
array (
0 => 'B',
1 => 170,
2 => 279,
),
2 =>
array (
0 => 'C',
1 => 15,
2 => 68,
),
3 =>
array (
0 => 'D',
1 => 210,
2 => 4,
),
4 =>
array (
0 => 'E',
1 => 287,
2 => 0,
),
)

Change key on array_chunk php

I have array based POST like this :
Array
(
[condition] => Array
(
[0] => 1
)
[container] =>
[cleaning] => Y
[owner] => Eagletainer
[last_cargo] => 1
[vessel] =>
[insulation] => 1
[tare] =>
[gross] =>
[capacity] =>
[unit_type] => IMO 1
[date_of_manu] =>
[name_manu] =>
[last25] =>
[cert25] =>
[last5] =>
[cert5] =>
[list2_item_0] => 1
[list2_kondisi_0] => 9
[list3_item_0] => 15
[list3_kondisi_0] => 3
[comments] =>
)
My case is, I want to chunk a lot of those element array into another array for insert_batch in my database.
This is the php code to chunk those array:
public function get_partition($array, $p, $c) {
$partition = array_slice($array, $p);
array_pop($partition);
return $chunk = array_chunk($partition, $c);
}
Now, use it,
$detail = $this->get_partition($this->input->post(), 17, 2);
The result is :
Array
(
[0] => Array
(
[0] => 1
[1] => 9
)
[1] => Array
(
[0] => 15
[1] => 3
)
)
My question in, how to change the key [0] and [1] into another key like [ID] and [CODE_DAMAGE]
I want them looked like this :
Array
(
[0] => Array
(
[ID] => 1
[CODE_DAMAGE] => 9
)
[1] => Array
(
[ID] => 15
[CODE_DAMAGE] => 3
)
)
Re-loop the array and achieve your desired result like this:
$detail = $this->get_partition($this->input->post(), 17, 2);
$new_array = array();
$count = 0;
foreach($detail as $row){
$new_array[$count]['ID'] = $row[0];
$new_array[$count++]['CODE_DAMAGE'] = $row[1];
}
If the indexes were already correct you could pass the optional third parameter: http://php.net/array_chunk
<?php
$array = array(0 => array(0 => 123, 1 => 1234), 1 => array(0 => 123, 1 => 1234));
$updatedArray = array();
foreach ($array as $k => $v) {
$updatedArray[$k]['ID'] = $v[0];
$updatedArray[$k]['CODE_DAMAGE'] = $v[1];
}
?>
Try this, I hope this helps.
Try this:
foreach($detail as $key => $value){
if($key == 0){
$detail['ID'] = $value;
unset($detail[$key]);
}
if($key == 1){
$detail['CODE_DAMAGE'] = $value;
unset($detail[$key]);
}
}
Just an example add your array to this code..it will work fine
$main = Array(Array(1,9),Array(15,3));
$b = array('ID', 'CODE_DAMAGE');
$new_array = array();
foreach($main as $subarray)
{
$new_array[] = array_combine($b, $subarray);
}
echo'<pre>';print_r($new_array);

merge two array with different dimension

I have array A and B with the structure:
A:
Array
(
[0] => 2013-08-01
[1] => 2013-08-02
[2] => 2013-08-03
[3] => 2013-08-04
)
and B:
Array
(
[0] => Array
(
[0] => 2013-08-01
[1] => 2
[2] => 0
[3] => 0
)
[1] => Array
(
[0] => 2013-08-02
[1] => 0
[2] => 4
[3] => 0
)
[2] => Array
(
[0] => 2013-08-04
[1] => 0
[2] => 1
[3] => 0
)
)
The question is I want to combine twi ARRAY (A & B) to be like this:
Array
(
[0] => Array
(
[0] => 2013-08-01
[1] => 2
[2] => 0
[3] => 0
)
[1] => Array
(
[0] => 2013-08-02
[1] => 0
[2] => 4
[3] => 0
)
[2] => Array
(
[0] => 2013-08-03
[1] => 0
[2] => 0
[3] => 0
)
[3] => Array
(
[0] => 2013-08-04
[1] => 0
[2] => 1
[3] => 0
)
)
How to merge the both of array?
function combine($a, $b) {
foreach($a as $item_a) {
foreach($b as $item_b) {
if(in_array($item_a, $item_b)) {
continue 2;
}
}
$b[] = array(
$item_a, 0, 0, 0
);
}
usort($b, function($a, $b){return $a[0] > $b[0];});
return $b;
}
<?
$a = Array
(
"2013-08-01",
"2013-08-02",
"2013-08-03",
"2013-08-04"
);
$b = Array
(
Array (
"2013-08-01",
2,
0,
0
),
Array (
"2013-08-02",
0,
4,
0
),
Array (
"2013-08-04",
0,
1,
0
)
);
foreach ($a as $a_item) {
$found = FALSE;
foreach ($b as $b_item) {
if($b_item[0]==$a_item) {
$found = TRUE;
}
}
if(!$found) {
$b[] = Array (
$a_item,
0,
0,
0
);
}
}
print_r ($b);
?>
This should work if you don't have a huge amount of data in the arrays. If you have a large amount of data you should probably do some redesign to make it faster.
Assuming that the core dates are in array B, my approach would be to loop through array A and add to array B if a date is found that is not already in array B.
foreach ($arrA as $datecheck) {
$blnAdd = 1;
foreach ($arrB as $compare) {
if ($compare[0] == $datecheck) {
// If found, don't add!
$blnAdd = 0;
}
}
if ($blnAdd == 1) {
$arrB[] = array($datecheck, 0, 0, 0);
}
}
// When done, sort array B
// Create helper array for multisort
$arrHelper = array();
foreach ($arrB as $data) {
$arrHelper = $data[0];
}
// Then, sort array B using values from helper array
array_multisort($arrHelper, $arrB);
Then, $arrB should contain the values you need.

Categories