I have this issue with multidimensional arrays.
Given the following multidimensional array:
Array(
[0] => Array("a", "b", "c")
[1] => Array("x", "y", "z")
[2] => Array("a", "b", "c")
[3] => Array("a", "b", "c")
[4] => Array("a", "x", "z")
)
I want to check its values and find duplicates (i.e. keys 0, 2 and 3) leaving just one key - value pair deleting the others, resulting in somthing like this:
Array(
[0] => Array("a", "b", "c")
[1] => Array("x", "y", "z")
[2] => Array("a", "x", "z")
)
How can I do that??
This will remove duplicate items from your array using array_unique():
$new_arr = array_unique($arr, SORT_REGULAR);
You can simply do it using in_array()
$data = Array(
0 => Array("a", "b", "c"),
1 => Array("x", "y", "z"),
2 => Array("a", "b", "c"),
3 => Array("a", "b", "c"),
4 => Array("a", "x", "z"),
);
$final = array();
foreach ($data as $array) {
if(!in_array($array, $final)){
$final[] = $array;
}
}
which will get you something like
array(3) {
[0] => array(3) {
[0] => string(1) "a"
[1] => string(1) "b"
[2] => string(1) "c"
}
[1] => array(3) {
[0] => string(1) "x"
[1] => string(1) "y"
[2] => string(1) "z"
}
[2] => array(3) {
[0] => string(1) "a"
[1] => string(1) "x"
[2] => string(1) "z"
}
}
You can go smart with serialization for comparison of arrays.
var_dump(makeUnique($data));
function makeUnique(array $data)
{
$serialized = array_map(create_function('$a', 'return serialize($a);'), $data);
$unique = array_unique($serialized);
return array_intersect_key($unique, $data);
}
Have fun
$arr = ...;
$final = array();
sort($arr);
foreach ($arr as $el) {
if (!isset($prev) || $el !== $prev)
$final[] = $el
$prev = $el;
}
This is a more efficient1 solution (log n + n instead of quadratic) but it relies on a total order between all the elements of the array, which you may not have (e.g. if the inner arrays have objects).
1 More efficient than using in_array. Turns out array_unique actually uses this algorithm, so it has the same shortcomings.
To check using array_unique on multidimensional arrays, you need to flatten it out like so, using implode.
$c=count($array)
for($i=0;$i<$c;$i++)
{
$flattened=implode("~",$array[$i]);
$newarray[$i]=$flattened;
}
if(count(array_unique($newarray)
<count($newarray))
{
//returns true if $array contains duplicates
//can also use array_unique on $newarray
//to remove duplicates, then explode,
//to return to default state
}
Hope this is helpful, took sometime to get it.
**This is example array**
$multi_com=[
[
{
"combination_id": "19"
},
{
"combination_id": "20"
},
{
"combination_id": "21"
}
],
[
{
"combination_id": "18"
},
{
"combination_id": "20"
},
{
"combination_id": "22"
}
],
[
{
"combination_id": "20"
},
{
"combination_id": "21"
}
]
]
**This is sample code**
$array1 = [];
$array2 = [];
$status = false;
foreach ($multi_com as $key => $val) {
foreach ($val as $key2 => $val2) {
if (count($array1) !== 0) {
$array_res = in_array($val2->combination_id, $array1);
if ($array_res) {
$array2[] = $val2->combination_id;
}
}
}
if (!$status) {
for ($x = 0; $x < count($val); $x++) {
$array1[] = $val[$x]->combination_id;
}
} else {
$array1 = [];
$array1 = $array2;
$array2 = [];
}
$status = true;
}
return $array1;
Related
Here I created Hashmap array in PHP. I gave input as $keys = str_split('cat1hen') which give output 'doga#nt'.
$rule =
[
"c" => "d",
"a" => "o",
"t" => "g",
"h" => "a",
"1" => "#",
"e" => "n",
"n" => "t"
];
$keys = str_split('cat1hen');
$output = [];
array_walk($keys,
function($item, $index) use($rule,$keys, &$output) {
if($rule[$item] == '#' && isset($keys[$index + 1])) {
$output[] = $rule[$keys[$index + 1]];
return;
}
if(isset($keys[$index - 1]) && $rule[$keys[$index - 1]] == '#') {
$output[] = '#';
return;
}
$output[] = $rule[$item];
return;
},
$keys);
echo implode($output);
Instead of giving one input value,I want to give input as array with many value i.e $keys = ['cat1hen','cathen','hencat'] which should give output as ['doga#nt','dogant','antdog'].How to modify code to do so??
I just slightly modified my code I answered your previous question with.
Added a foreach to loop the words.
$rule =
[
"c" => "d",
"a" => "o",
"t" => "g",
"h" => "a",
"1" => "#",
"e" => "n",
"n" => "t"
];
$orders = ['cat1hen','cathen','hencat'];
foreach($orders as $order){
$arr = str_split($order);
$str ="";
foreach($arr as $key){
$str .= $rule[$key];
}
$str = preg_replace("/(.*?)(#)(.)(.*)/", "$1$3$2$4", $str);
echo $str . "\n";
}
//doga#nt
//dogant
//antdog
https://3v4l.org/LhXa3
As another solution without regexps, you can wrap your array_walk into a function and map it to each element of array:
function myFunction($sourceString)
{
$rule =
[
"c" => "d",
"a" => "o",
"t" => "g",
"h" => "a",
"1" => "#",
"e" => "n",
"n" => "t"
];
$keys = str_split($sourceString);
$output = [];
array_walk($keys,
function ($item, $index) use ($rule, $keys, &$output) {
if ($rule[$item] == '#' && isset($keys[$index + 1])) {
$output[] = $rule[$keys[$index + 1]];
return;
}
if (isset($keys[$index - 1]) && $rule[$keys[$index - 1]] == '#') {
$output[] = '#';
return;
}
$output[] = $rule[$item];
return;
},
$keys);
return implode($output);
}
print_r(array_map('myFunction', ['cat1hen','cathen','hencat']));
Sample fiddle.
I need to merge multiple arrays into one where a specific key & its value are same. Here is the Sample_Array1
array(n) {
[0]=> array {
["a"]=> "m1"
["b"]=> "x2"
}
[1]=> array {
["a"]=> "n1"
["b"]=> "y2"
} ....
Sample_Array2 with one common key & other different ones.
array(n) {
[0]=> array {
["b"]=> "x2"
["c"]=> "p1"
}
[1]=> array {
["b"]=> "x2"
["d"]=> "q1"
}
[2]=> array {
["b"]=> "y2"
["e"]=> "r1"
} ....
Need to merge / append Sample_Array2 to Sample_Array1 where key-"b" & its value are same. The expected output:
array(n) {
[0]=>
array(2) {
["a"]=> "m1"
["b"]=> "x2"
["c"]=> "p1"
["d"]=> "q1"
}
[1]=>
array(2) {
["a"]=> "n1"
["b"]=> "y2"
["e"]=> "r1"
} ....
I have tried so many similar questions but couldn't find the exact result.
PHP merge arrays with a condition The answer given on this link is not solving the purpose, its making different array for each new key, while I need to append the new keys in one array.
This should work, assuming you have the "b" index in all sub arrays.
$array1 = array();
$array1[] = array("a" => "m1", "b" => "x2", "c" => null);
$array1[] = array("a" => "n1", "b" => "y2");
$array2 = array();
$array2[] = array("b" => "x2", "c" => "p1");
$array2[] = array("a" => null, "b" => "x2", "d" => "q1");
$array2[] = array("b" => "y2", "e" => "r1");
function merge_on_key($array1, $array2, $key) {
$result_array = array();
foreach($array1 as $key1 => $sub_array1) {
$merged_array = array();
$sub_array1 = array_filter($sub_array1);
foreach($array2 as $key2 => $sub_array2) {
$sub_array2 = array_filter($sub_array2);
if($sub_array1[$key] == $sub_array2[$key]) {
$merged_array = array_merge($sub_array1, $sub_array2, $merged_array);
unset($array2[$key2]);
}
}
if (!empty($merged_array)) {
$result_array[] = $merged_array;
}
}
return array_merge($result_array, $array2);
}
$final_array = merge_on_key($array1, $array2, "b");
print_r($final_array);
In case you have to match the "b" index within the $array1 itself too, then simply use it twice:
$array1 = merge_on_key($array1, $array1, "b");
$final_array = merge_on_key($array1, $array2, "b");
i really have no idea what you want to achieve here - but based on your description the following code works
$arrA = [
0 =>
[
'a' => 'm1',
'b' => 'x2'
],
1 =>
[
'a' => 'n1',
'b' => 'y2'
]
];
$arrB = [
0 =>
[
'b' => 'x2',
'c' => 'p1',
],
1 =>
[
'b' => 'x2',
'd' => 'q1',
],
2 =>
[
'b' => 'y2',
'e' => 'r1',
],
];
foreach($arrB AS $arrData)
{
foreach($arrData AS $key => $val)
{
if ((isset($arrData['a']) && $arrData['a'] == $arrA[0]['a']) || (isset($arrData['b']) && $arrData['b'] == $arrA[0]['b']))
{
$arrA[0][$key] = $val;
}
elseif ((isset($arrData['b']) && $arrData['b'] == $arrA[1]['a']) || (isset($arrData['b']) && $arrData['b'] == $arrA[1]['b']))
{
$arrA[1][$key] = $val;
}
}
}
print_r($arrA);
Created the arrays similar to yours. $new_array is the resultant array that you are looking for.
$a=array();
$a[0]=array('a'=>'m1', 'b'=>'x2');
$a[1]=array('a'=>'n1', 'b'=>'y2');
$b=array();
$b[0]=array('b'=>'x2', 'c'=>'p1');
$b[1]=array('b'=>'x2', 'd'=>'q1');
$b[2]=array('b'=>'y2', 'e'=>'r1');
foreach($a as $row){
//echo '<pre>'; print_r($row);
foreach($b as $c=>$row1){
//echo '<pre>'; print_r($row1);echo $c;die;
if($row['b']==$row1['b']){
$new_array[]=array_merge($row, $row1);
}
}
}echo '<pre>'; print_r($new_array);
// Gather all values of b from both arrays
$all_b = array_unique(array_merge(array_column($arr1, 'b'), array_column($arr2, 'b')));
$res = [];
// For each b value
foreach($all_b as $b) {
$temp = [];
// Scan the arrays for items with the same b value
foreach($arr1 as $a1) {
if ($a1['b'] == $b) $temp = array_merge($temp, $a1);
}
foreach($arr2 as $a2) {
if ($a2['b'] == $b) $temp = array_merge($temp, $a2);
}
// Save them to new array
$res[] = $temp;
}
print_r($res);
demo on eval
I have 2 arrays:
array1 :
[0]=>
string(10) "AAAAAAAAAAA"
[1]=>
string(10) "BBBBBBBBBBB"
...
and array2:
[0]=>
float(0)
[550]=>
float(55)
...
I need a result like this:
"AAAAAAAAAAA" : 0 : 0
"BBBBBBBBBBB" : 550: 55
...
i.e. how to combine the arrays. How do i get that?
suppose you two arrays have the same length,
$keys = array_keys($array1);
$values = [];
foreach($array2 as $k=>$v)
{
$values[] = $k.':'.$v;
}
$result = array_combine($keys, $values);
The result you want is not clear... if each rows are just a string, this should work :
$a = [
0 => "AAAAAAAAAAA",
1 => "BBBBBBBBBBB"
];
$b = [
0 => (float) 0,
550 => (float) 55
];
$result = array_map(
function($v1, $v2, $v3) {
return "$v1 : $v2 : $v3";
},
$a, array_keys($b), $b
);
var_dump($result);
I am trying to combine keys when they have similar values, and expect the result as a string. Actually I had no idea how to achieve this, although I run a few tests.
$array = array(
'a' => 65,
'b' => 31,
'c' => 100,
'd' => 31,
'e' => 31,
'f' => 31,
'h' => 23,
'i' => 23,
'j' => 23,
'k' => 23,
'l' => 48,
'm' => 48,
);
$results = array();
foreach ($array as $k => $v) {
// This is my attempt among others to no luck.
// Can not use array_key_exists because values are unpredictable.
$similars[$v] = $k;
$results[$v] = implode(", ", array_unique($similars)) . ' : ' . $v;
}
var_dump(implode("\n ", $results));
You can view the output:
http://codepad.org/ECekF3dq
I am almost there, but obviously wrong :(
Not expected:
string(72) "a : 65
a, f, c : 31
a, b, c : 100
a, f, c, k : 23
a, f, c, k, m : 48"
Expected:
a : 65
b, d, e, f : 31
c : 100
h, i, j, k : 23
l, m : 48
Those with the same values should collapse as one line.
Thanks for any hint.
You want to make $similars into an array of arrays. That way you can keep all the keys with that value.
$results = array();
$similars = array();
foreach ($array as $k => $v) {
if(!isset($similars[$v])){
$similars[$v] = array($k);
}
else{
$similars[$v][] = $k;
}
$results[$v] = implode(", ", $similars[$v]) . ' : ' . $v;
}
var_dump(implode("\n ", $results));
There might be a more elegant way of doing this, but I'd probably use two simple foreach loops:
function parseArray($data)
{
$tmp = array();
foreach ($data as $key => $item) {
// Check if we already created this key
if (isset($tmp[$item])) {
// Append if so
$tmp[$item] .= ', '.$key;
} else {
// Init if not
$tmp[$item] = $key;
}
}
// Now we stringify the tmp array.
$result = '';
foreach ($tmp as $key => $value) {
$result .= "$key : $value\n";
}
return $result;
}
$tmp = array();
foreach ($array as $k => $v) $tmp[$v][] = $k;
foreach ($tmp as $k => $v) echo implode(', ', $v) . ' : ' . $k . "\n<br />";
I think reversing the keys and values could be beneficial. Turn the integers into keys, and the chars into array values. This would enable you to maintain the desired one-to-many relationship:
$array = array(
'a' => 65,
'b' => 31,
'c' => 100,
'd' => 31,
'e' => 31,
'f' => 31,
'h' => 23,
'i' => 23,
'j' => 23,
'k' => 23,
'l' => 48,
'm' => 48,
);
$results = array();
foreach ($array as $k => $v) {
$results[$v][]=$k;
}
foreach ($results as $k=>$v) {
echo implode(',',$v) . " : " . $k . "\r\n";
}
the multidimensional array $results equals:
array(5) {
[65]=>
array(1) {
[0]=>
string(1) "a"
}
[31]=>
array(4) {
[0]=>
string(1) "b"
[1]=>
string(1) "d"
[2]=>
string(1) "e"
[3]=>
string(1) "f"
}
[100]=>
array(1) {
[0]=>
string(1) "c"
}
[23]=>
array(4) {
[0]=>
string(1) "h"
[1]=>
string(1) "i"
[2]=>
string(1) "j"
[3]=>
string(1) "k"
}
[48]=>
array(2) {
[0]=>
string(1) "l"
[1]=>
string(1) "m"
}
}
Final output:
a : 65
b,d,e,f : 31
c : 100
h,i,j,k : 23
l,m : 48
Try this
$array = array('a' => 65,'b' => 31,'c' => 100,'d' => 31,'e' => 31,'f' => 31,'h' => 23,
'i' => 23,'j' => 23,'k' => 23,'l' => 48,'m' => 48);
$similars = array();
foreach ($array as $k => $v) {
// This is my attempt among others to no luck.
// Can not use array_key_exists because values are unpredictable.
$key = array_search($v, $similars);
if (isset($similars[$key])) {
unset($similars[$key]);
$similars[$key.','.$k] = $v;
}
else
$similars[$k] = $v;
}
print_r($similars);
//display as expected
foreach($similars as $k => $v)
echo "</br>".$k.':'.$v;
I use this code :
$new = array(
"123" => "a",
"456" => "b"
);
$old = array(
"123" => "a",
"456" => "b"
);
then the $new array become like this:
$new = array(
"456" => "b",
"123" => "c",
"789" => "e"
);
as you see the count of $new array increased and the order of elements changed and the value at key 123 also changed. I need to compare the $new array against the $old array and catch only the change made on the value at key 123 without caring about the order and the count of elements. I tried:
$result = array_diff( $new, $old );
print_r( $result );
output :
Array ( [123] => c [789] => e )
UPDATE. quite confusing. now I think we got it
$old = array(
"123" => "a",
"456" => "b"
);
$new = array(
"456" => "b",
"123" => "c", // catch this (element in old array that is changed)
"789" => "e"
);
$new2 = array();
foreach ($new as $key => $new_val)
{
if (isset($old[$key])) // belongs to old array?
{
if ($old[$key] != $new_val) // has changed?
$new2[$key] = $new[$key]; // catch it
}
}
// output $new2:
array (
123 => 'c',
)
You first of all want to have those elements of $new that are changed compared to $old (see array_diff_assoc):
$changed = array_diff_assoc($new, $old);
Of that result you want to have only those elements that have their key in $old (see array_intersect_key):
$result = array_intersect_key($changed, $old);
And that's it. You can wrap that into each other if it helps:
array_intersect_key(array_diff_assoc($new, $old), $old);
Result is:
array(1) {
[123] =>
string(1) "c"
}
Full example (Demo):
$old = array(
"123" => "a",
"456" => "b"
);
$new = array(
"456" => "b",
"123" => "c", // catch only the change made on the value at key 123
"789" => "e"
);
$changed = array_diff_assoc($new, $old);
$result = array_intersect_key($changed, $old);
var_dump($result);
Just a final note: There are many array functions in PHP. It's worth to go through the list and look what is fitting because most often you only need one or two of them to get things like these done.
You use this code for your requirements
<?php
function key_compare_func($key1, $key2)
{
if ($key1 == $key2)
return 0;
else if ($key1 > $key2)
return 1;
else
return -1;
}
$array1 = array('blue' => 1, 'red' => 2, 'green' => 3, 'purple' => 4);
$array2 = array('green' => 5, 'blue' => 6, 'yellow' => 7, 'cyan' => 8);
var_dump(array_intersect_ukey($array1, $array2, 'key_compare_func'));
?>