PHP: Delete unique values from an array - php

I would like to delete all unique values from an array.
So lets say I have $array = (1,2,3,5,4,3,4,5,234)
the function should delete all unique values and output:
$newarray = (3,5,4,3,4,5)
I just thought of a solution with array_count_values but I do not know how I could iterate it. Furthermore I am sure there is a more elegant and efficient way to do this. Thank you for your help in advance.

One of solutions:
$array = [1,2,3,5,4,3,4,5,234];
$freq = array_count_values($array);
print_r(array_filter(
$array,
function ($v) use ($freq) { return 1 < $freq[$v]; }
));

$array = (1,2,3,5,4,3,4,5,234);
$freq = array_count_values($array);
$output = array();
foreach($array as $val){
if($freq[$val] >1){
$output[] = $val;
}
}
print_r($output);
May be not the most efficient way.

Related

Replace array value with more than one values

I have an array like this,
$array = array(
1,2,3,'4>12','13.1','13.2','14>30'
);
I want to find any value with an ">" and replace it with a range().
The result I want is,
array(
1,2,3,4,5,6,7,8,9,10,11,12, '13.1', '13.2', 14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30
);
My understanding:
if any element of $array has '>' in it,
$separate = explode(">", $that_element);
$range_array = range($separate[0], $separate[1]); //makes an array of 4 to 12.
Now somehow replace '4>12' of with $range_array and get a result like above example.
May be I can find which element has '>' in it using foreach() and rebuild $array again using array_push() and multi level foreach. Looking for a more elegant solution.
You can even do it in a one-liner like this:
$array = array(1,2,3,'4>12','13.1','13.2','14>30');
print_r(array_reduce(
$array,
function($a,$c){return array_merge($a,#range(...array_slice(explode(">","$c>$c"),0,2)));},
[]
));
I avoid any if clause by using range() on the array_slice() array I get from exploding "$c>$c" (this will always at least give me a two-element array).
You can find a little demo here: https://rextester.com/DXPTD44420
Edit:
OK, if the array can also contain non-numeric values the strategy needs to be modified: Now I will check for the existence of the separator sign > and will then either merge some cells created by a range() call or simply put the non-numeric element into an array and merge that with the original array:
$array = array(1,2,3,'4>12','13.1','64+2','14>30');
print_r(array_reduce(
$array,
function($a,$c){return array_merge($a,strpos($c,'>')>0?range(...explode(">",$c)):[$c]);},
[]
));
See the updated demo here: https://rextester.com/BWBYF59990
It's easy to create an empty array and fill it while loop a source
$array = array(
1,2,3,'4>12','13.1','13.2','14>30'
);
$res = [];
foreach($array as $x) {
$separate = explode(">", $x);
if(count($separate) !== 2) {
// No char '<' in the string or more than 1
$res[] = $x;
}
else {
$res = array_merge($res, range($separate[0], $separate[1]));
}
}
print_r($res);
range function will help you with this:
$array = array(
1,2,3,'4>12','13.1','13.2','14>30'
);
$newArray = [];
foreach ($array as $item) {
if (strpos($item, '>') !== false) {
$newArray = array_merge($newArray, range(...explode('>', $item)));
} else {
$newArray[] = $item;
}
}
print_r($newArray);

Unique php multidimensional array and sort by occurrence

I have a PHP multiD array like:-
$a = array($arrayA, $arrayB, $arrayA, $arrayC, $arrayC, $arrayA...........)
how can I get a resulting array which have distinct elements from this array and sorted with the more occurrence first like:-
array( $arrayA, $arrayB, $arrayC)
because array $arrayA was 3 times in first array so it comes first in resulting array.
I have tried :-
$newArray = array();
$count = count($a);
$i = 0;
foreach ($a as $el) {
if (!in_array($el, $newArray)) {
$newArray[$i] = $el;
$i++;
}else{
$oldKey = array_search($el, $newArray);
$newArray[$oldKey+$count] = $el;
unset($newArray[$oldKey]);
}
}
krsort($newArray);
This is perfectly working but this is very lengthy process because my array has thousands of elements. Thanks in advance for your help.
Try like this :-
$input = array_map("unserialize", array_unique(array_map("serialize", $input)));
Like #saravanan answer but result sorted:-
<?php
$input = [['b'],['a'],['b'],['c'],['a'],['a'],['b'],['a']];
$result = array_count_values( array_map("serialize", $input));
arsort($result,SORT_NUMERIC);
$result = array_map("unserialize",array_keys($result));
print_r($result);

How to create an array of arrays from another array filtering it by a specific key of the subarrays?

I have following array of arrays:
$array = [
[A,a,1,i],
[B,b,2,ii],
[C,c,3,iii],
[D,d,4,iv],
[E,e,5,v]
];
From this one, I would like to create another array where the values are extract only if the value of third key of each subarray is, for example, greater than 3.
I thought in something like that:
if $array['2'] > 3){
$new_array[] = [$array['0'],$array['2'],$array['3']];
}
So in the end we would have following new array (note that first keys of the subarrays were eliminate in the new array):
$new_array = [
[D,4,iv],
[E,5,v]
];
In general, I think it should be made with foreach, but on account of my descripted problem I have no idea how I could do this. Here is what I've tried:
foreach($array as $value){
foreach($value as $k => $v){
if($k['2'] > 3){
$new_array[] = [$v['0'], $v['2'], $v['3']];
}
}
}
But probably there's a native function of PHP that can handle it, isn't there?
Many thanks for your help!!!
Suggest you to use array_map() & array_filter(). Example:
$array = [
['A','a',1,'i'],
['B','b',2,'ii'],
['C','c',3,'iii'],
['D','d',4,'iv'],
['E','e',5,'v']
];
$newArr = array_filter(array_map(function($v){
if($v[2] > 3) return [$v[0], $v[2], $v[3]];
}, $array));
print '<pre>';
print_r($newArr);
print '</pre>';
Reference:
array_map()
array_filter()
In the first foreach, $v is the array you want to test and copy.
You want to test $v[2] and check if it match your condition.
$new_array = [];
foreach($array as $v) {
if($v[2] > 3) {
$new_array[] = [$v[0], $v[2], $v[3]];
}
}

Remove common items from multiple arrays

$array1 = array("a","b");
$array2 = array("b","c");
I want the following array from above arrays containing items which are not common in both arrays.
$output = array("a","c");
I have tried folloing
$output = array_diff($array1,$array2);
How can do it. Thanks.
Just make subtraction of union and intersection:
$array1 = array("a","b");
$array2 = array("b","c");
$output = array_diff(array_merge($array1, $array2), array_intersect($array1, $array2));
Use:
$array1 = array("a","b");
$array2 = array("b","c");
$output = array("a","c");
$output = array_merge(array_diff($array1,$array2),array_diff($array2,$array1));
print_r($output);
So I read earlier today about how array_merge was considered slow. I also read the same about array_diff, specifically here. This got me to thinking that using both at once could be particularly expensive, so I put the following experiment together:
I expanded upon merlyn's function to come up with this:
function multiArrayUnique($array1, $array2)
{
//leaves array1 intact
$arrayFrom1=$array1;
$arrayAgainst = array_flip($array2);
foreach ($arrayFrom1 as $key => $value) {
if(isset($arrayAgainst[$value])) {
unset($arrayFrom1[$key]);
}
}
//arrayFrom1=array("a");
$arrayFrom2=$array2;//b,c
$arrayAgainst = array_flip($array1);//a,b
foreach ($arrayFrom2 as $key => $value) {
if(isset($arrayAgainst[$value])) {
unset($arrayFrom2[$key]);
}
}
//arrayFrom2=array("c");
foreach ($arrayFrom2 as $item) {
array_push($arrayFrom1, $item);
}
return $arrayFrom1;
}
Using the OP's example, this function also returns array("a","c").
Now, that is a monstrous amount of code, and it it difficult to read... but, here is the efficiency it buys on a large data set:
$a1 = range(0,25000);
$a2 = range(15000,50000);
$start=microtime(true);
$output = array_diff(array_merge($a1, $a2), array_intersect($a1, $a2));
$end=microtime(true);
echo $end-$start."<hr>";
7.5844340324402
$start=microtime(true);
$output = array_merge(array_diff($a1,$a2),array_diff($a2,$a1));
$end=microtime(true);
echo $end-$start."<hr>";
6.551374912262
$start=microtime(true);
$result=multiArrayUnique($a1,$a2);
$end=microtime(true);
echo $end-$start."<hr>";
0.21001195907593
So while the function's code is considerably more complex, and may have other limitations, it's implementation is still a one-liner, and the processing time is 14x faster.

php explode and force array keys to start from 1 and not 0

I have a string that will be exploded to get an array, and as we know, the output array key will start from 0 as the key to the first element, 1 for the 2nd and so on.
Now how to force that array to start from 1 and not 0?
It's very simple for a typed array as we can write it like this:
array('1'=>'value', 'another value', 'and another one');
BUT for an array that is created on the fly using explode, how to do it?
Thanks.
$exploded = explode('.', 'a.string.to.explode');
$exploded = array_combine(range(1, count($exploded)), $exploded);
var_dump($exploded);
Done!
Just use a separator to create a dummy element in the head of the array and get rid of it afterwards. It should be the most efficient way to do the job:
function explode_from_1($separator, $string) {
$x = explode($separator, $separator.$string);
unset($x[0]);
return $x;
}
a more generic approach:
function explode_from_x($separator, $string, $offset=1) {
$x = explode($separator, str_repeat($separator, $offset).$string);
return array_slice($x,$offset,null,true);
}
$somearray = explode(",",$somestring);
foreach($somearray as $key=>$value)
{
$otherarray[$key+1] = $value;
}
well its dirty but isn't that what php is for...
Nate almost had it, but needed a temporary variable:
$someArray = explode(",",$myString);
$tempArray = array();
foreach($someArray as $key=>$value) {
$tempArray[$key+1] = $value;
}
$someArray = $tempArray;
codepad example
$array = array('a', 'b', 'c', 'd');
$flip = array_flip($array);
foreach($flip as &$element) {
$element++;
}
$normal = array_flip($flip);
print_r($normal);
Try this, a rather funky solution :P
EDIT: Use this instead.
$array = array('a', 'b', 'b', 'd');
$new_array = array();
$keys = array_keys($array);
for($i=0; $i<count($array); $i++) {
$new_array[$i+1] = $array[$i];
}
print_r($new_array);
I agree with #ghoti that this task is probably an XY Problem. I can't imagine a valid/professional reason to start keys from 1 -- I've never needed this functionality in over 10 years of development. I'll offer a compact looping approach, but I'll probably never need it myself.
After instatiating a counter which is one less than the desired first key, you can use a body-less foreach() as a one-liner.
Code: (Demo)
$i = 0;
$result = [];
foreach (explode('.', 'a.string.to.explode') as $result[++$i]);
var_export($result);

Categories