I want to remove some duplicate values on an array, but there is a condition that the script has to ignore the array that contains a specific word.
Below code is adapted from PHP: in_array.
$array = array( 'STK0000100001',
'STK0000100002',
'STK0000100001', //--> This should be remove
'STK0000100001-XXXX', //--> This should be ignored
'STK0000100001-XXXX' ); //--> This should be ignored
$ignore_values = array('-XXXX');
if(make_unique($array, $ignore_values) > 0) {
//ERROR HERE
}
The function to make the array unique is:
function make_unique($array, $ignore) {
$i = 0;
while($values = each($array)) {
if(!in_array($values[1], $ignore)) {
$dupes = array_keys($array, $values[1]);
unset($dupes[0]);
foreach($dupes as $rmv) {
$i++;
}
}
}
return $i;
}
I have tried to use if(!in_array(str_split($values[1]), $ignore)) ... but it just the same.
The array should become like:
STK0000100001
STK0000100002
STK0000100001-XXXX
STK0000100001-XXXX
How to do that?
Try this one, just remove the print_r(); inside the function when using in production
if(make_unique($array, $ignore_values) > 0) {
//ERROR HERE
}
function make_unique($array, $ignore) {
$array_hold = $array;
$ignore_val = array();
$i = 0;
foreach($array as $arr) {
foreach($ignore as $ign) {
if(strpos($arr, $ign)) {
array_push( $ignore_val, $arr);
unset($array_hold[$i]);
break;
}
}
$i++;
}
$unique_one = (array_unique($array_hold));
$unique_one = array_merge($unique_one,$ignore_val);
print_r($unique_one);
return count($array) - count($unique_one);
}
This should work for >= PHP 5.3.
$res = array_reduce($array, function ($res, $val) use ($ignore_values) {
$can_ignore = false;
foreach ($ignore_values as $ignore_val) {
if (substr($val, 0 - strlen($ignore_val)) == $ignore_val) {
$can_ignore = true;
break;
}
}
if ( $can_ignore || ! in_array($val, $res)) {
$res[] = $val;
}
return $res;
}, array()
);
Otherwise
$num_of_duplicates = 0;
$res = array();
foreach ($array as $val) {
$can_ignore = false;
foreach ($ignore_values as $ignore_val) {
if (substr($val, 0 - strlen($ignore_val)) == $ignore_val) {
$num_of_duplicates++;
$can_ignore = true;
break;
}
}
if ( $can_ignore || ! in_array($val, $res)) {
$res[] = $val;
}
}
Edit: Added duplicate count to the second snippet.
Related
I have an array:
$arr1 = [1,2,2,3,3,3];
Is there any method by which I can delete a duplicate value once like,
some_function($arr1,3);
which gives me the ouput $arr1 = [1,2,2,3,3]
As per the comment, check if there are more than one of the element you're searching for, then find and remove one of them.
function remove_one_duplicate( $arr, $target ) {
if( count( array_keys( $arr, $target ) ) > 1 ) {
unset( $arr[array_search( $target, $arr )] );
}
return $arr;
}
This should work...
function removeduplicate($myarray,$needle) {
if (($nmatches = count($matches = array_keys($myarray,$needle))) >= 2) {
for ($i=0; $i<$nmatches; $i++) {
if ($matches[$i+1] == (1+$matches[$i])) {
array_splice($myarray,$matches[$i],1);
break;
}
}
}
return $myarray;
}
To use the function...
$arr1 = [1,2,2,3,3,3,4,7,3,3];
$newarray = removeduplicate($arr1,3)
print_r($newarray);
EDITED:
If you want the function to modify your original array directly, you can do it (the function will return true if a character has been removed or false if not)...
function removeduplicate(&$myarray,$needle) {
if (($nmatches = count($matches = array_keys($myarray,$needle))) >= 2) {
for ($i=0; $i<$nmatches; $i++) {
if ($matches[$i+1] == (1+$matches[$i])) {
array_splice($myarray,$matches[$i],1);
return true;
}
}
}
return false;
}
So, now you can do...
$arr1 = [1,2,2,2,2,2,3,3,3,4,2,2];
removeduplicate($arr1,2);
print_r($arr1);
This function will copy the array skipping only the second instance of the specified element.
function removeOnce($array, $elem) {
$found = 0;
$result = [];
foreach ($array as $x) {
if ($x == $elem && (++$found) == 2) {
continue;
}
$result[] = $x;
}
return $result;
}
$val = array();
foreach ($value as $key) {
$nested = $this->Mdl_mymodel->arr($key);
if($nested != NULL) {
$n = 0;
foreach ($nested as $nest) {
$n++;
$val[$n] = $nest->num;
}
}
else {
$val = '';
}
print_r($val);
}
print_r($val);
Here $val inside the loop is printed but outside it is empty. I think i am missing something. Please help!
Note: I am using codeigniter.
$val = array();
foreach ($value as $key) {
$nested = $this->Mdl_mymodel->arr();
if($nested != NULL) {
$n = 0;
foreach ($nested as $nest) {
$n++;
$val[$n] = $nest->num;
}
}
else {
// $val = ''; Commented this line because you have already
// initialized $val. If you do not get records,
// it will return as blank array.
}
print_r($val);
}
print_r($val);
I have two arrays like
$a1= array(
array('a'=>1,'b'=>2, 'c'=>3), // similar to $a2[0]
array('a'=>3,'b'=>4, 'c'=>5), // similar to $a2[1]
array('a'=>9,'b'=>6, 'c'=>9)
);
$a2= array(
array('a'=>1,'b'=>2, 'c'=>3),
array('a'=>3,'b'=>4, 'c'=>5),
array('a'=>5,'b'=>6, 'c'=>7),
array('a'=>11,'b'=>4, 'c'=>13),
array('a'=>14,'b'=>6, 'c'=>3)
);
I want a resulting array that does't have common values like
$arrayResult= array(
array('a'=>9,'b'=>6, 'c'=>9),// from $a1[3]
array('a'=>5,'b'=>6, 'c'=>7),// from $a2[2]
array('a'=>11,'b'=>4, 'c'=>13),// from $a2[3]
array('a'=>14,'b'=>6, 'c'=>3)// from $a2[4]
);
I have tried array_udiff, and also separate function but I'm unable to get the right thing.
Hmm fast solution, not optimized
$result = array();
foreach($a1 as $va1) {
$found = false;
foreach($a2 as $va2) {
$x = array_diff($va1, $va2);
if (empty($x)) {
$found = true;
}
}
if (!$found) {
$result[] = $va1;
}
}
foreach($a2 as $va2) {
$found = false;
foreach($a1 as $va1) {
$x = array_diff($va2, $va1);
if (empty($x)) {
$found = true;
}
}
if (!$found) {
$result[] = $va2;
}
}
var_dump($result);
EDIT: A little optimized (unseting values that were found before):
$a1= array(
array('a'=>1,'b'=>2, 'c'=>3), // similar to $a2[0]
array('a'=>3,'b'=>4, 'c'=>5), // similar to $a2[1]
array('a'=>9,'b'=>6, 'c'=>9)
);
$a2= array(
array('a'=>1,'b'=>2, 'c'=>3),
array('a'=>3,'b'=>4, 'c'=>5),
array('a'=>5,'b'=>6, 'c'=>7),
array('a'=>11,'b'=>4, 'c'=>13),
array('a'=>14,'b'=>6, 'c'=>3)
);
$i=0;
$result = array();
foreach($a1 as $ka1 => $va1) {
$found = false;
foreach($a2 as $ka2 => $va2) {
$i++;
$x = array_diff($va1, $va2);
if (empty($x)) {
$found = true;
unset($a2[$ka2], $a1[$ka1]);
}
}
if (!$found) {
$result[] = $va1;
}
}
foreach($a2 as $ka2 => $va2) {
$found = false;
foreach($a1 as $ka1 => $va1) {
$i++;
$x = array_diff($va2, $va1);
if (empty($x)) {
unset($a2[$ka2], $a1[$ka1]);
$found = true;
}
}
if (!$found) {
$result[] = $va2;
}
}
var_dump($result);echo $i;
function check_diff_multi($array1, $array2){
$result = array();
foreach($array1 as $key => $val) {
if(isset($array2[$key])){
if(is_array($val) && is_array($array2[$key])){
$result[$key] = check_diff_multi($val, $array2[$key]);
}
} else {
$result[$key] = $val;
}
}
return $result;
}
//call this function
check_diff_multi($a1,$a2);
I wasn't so clear in my first question, so i deleted it and here is a reformulation;
I have those arrays:
$open = array(array("FAI1","34"),array("FAI2","34"),array("FAI3","34"));
$click = array(array("FAI2","52"),array("FAI1","68"),array("FAI3","99"));
$unsubscribe = array(array("FAI2","103"),array("FAI3","67"),array("FAI1","102"));
$def_sent = array(array("FAI1","34",24),array("FAI2","34",23),array("FAI3","34",27));
$SB = array(array("FAI2","103"),array("FAI3","67"),array("FAI1","102"));
$HB = array(array("FAI2","103"),array("FAI3","67"),array("FAI1","102"));
I searched for a function to merge them and get a result like this:
$result = array(array("FAI1",34,68,102,34,24,102,102)
,array("FAI2","34",23.....),
array("FAI3","34",27....));
and to do this, i used the function, in the php online documentation, and this is the function
function array_merge_recursive() {
$arrays = func_get_args();
$base = array_shift($arrays);
foreach ($arrays as $array) {
reset($base);
while (list($key, $value) = #each($array)) {
if (is_array($value) && #is_array($base[$key])) {
$base[$key] = array_merge_recursive($base[$key], $value);
} else {
$base[$key] = $value;
}
}
}
return $base;
}
But instead of getting the result above i got this:
FAI1|34
FAI2|34
FAI3|34
FAI2|52
FAI1|68
FAI3|99
...
So i need some help to reformulate this function to get the expected result.
Try this function:
function array_merge_rec() {
$arrays = func_get_args();
$result = array();
foreach ($arrays as $arg) {
if (is_array($arg)) {
foreach ($arg as $item) {
if (!isset($result[$item[0]])) {
$result[$item[0]] = $item;
} else {
$result[$item[0]][] = $item[1];
}
}
} else {
echo "$arg skippend because it isn't array\n";
}
}
return array_values($result);
}
Does it help?
There is an array:
$bounds = array([0]=>array('lower'=>2,'upper'=>5),
[1]=>array('lower'=>0,'upper'=>3));
and a variable:
$val = 4;
Is there any PHP function that can say whether $val belongs to any interval defined by 'lower' and 'upper' bounds in $bounds array? In this example 4 belongs to the 1st interval [2; 5]. So, the answer should be 'true'.
I don't think there is a built-in function to do this.
However, you can do it with a foreach statement:
function check_interval($bounds, $val) {
foreach ($bounds as $array) {
if($array['lower'] <= $val && $array['upper'] >= $val)
return true;
}
return false;
}
I'm not aware of any. You'll probably have to code it. Something like this will do:
function isFromInterval($bounds, $val) {
foreach ($bounds as $value) {
if ($val >= $value['lower'] && $val <= $value['upper']) {
return true;
}
}
return false;
}
No.
You would have to make a loop for the array like this
$val = 4;
$key_id = FALSE;
foreach($bounds as $key => $data){
if($val <= $data['upper'] AND $val >= $data['lower']){
$key_id = $key;
break;
}
}
if($key_id !== FALSE){
// found something
// $bounds[$key_id] is your result in the array
} else {
// found nothing
}
As a function
function find_range($bounds=array(), $val=0, $return_key=TRUE){
if(is_array($bounds) === FALSE){
$bounds = array();
}
if(is_numeric($val) === FALSE){
$val = 0;
}
if(is_bool($return_key) === FALSE){
$return_key = TRUE;
}
$key_id = FALSE;
foreach($bounds as $key => $data){
if($val < $data['upper'] AND $val > $data['lower']){
$key_id = $key;
break;
}
}
if($key_id !== FALSE){
return ($return_key === TRUE ? $key_id : TRUE);
} else {
return FALSE;
}
}
No, but you can do:
$bounds = array(3=>array('lower'=>2,'upper'=>5),
4=>array('lower'=>0,'upper'=>3));
$val = 4;
foreach($bounds as $num => $bound){
if(max($bound) >= $val && $val >= min($bound)){
echo $num;
}
}