Here is my problem:
I have an array with id's ($arr) which I'm slicing in groups of three. Next, I have an array with other id's ($otherIds) which I want to compare with main array ($arr), and if some of id's are identical - they should be deleted from rest of the $arr's chunks.
F.e. I have $arr = array(1, 2, 3, 4, 5, 6, 7, 8), and $otherIds = array(5, 7). I'm cutting $arr into the chunks of three elements, and then loop $arr in foreach and compare them to $otherIds, so in first iteration - code should see that $otherIds '5' and '7' exists in next chunks of $arr, and delete them.
My output should be:
1st iteration - array(1, 2, 3)
2nd iteration - array(4, 6) - 5 should be removed
3rd iteration - array(8) - 7 should be removed
$otherIds can be different in each iteration (they are taken from database), but to simplify it, I will use constant values.
Here is my code:
$arr = array(15, 10, 12, 17, 21, 13, 15, 25, 7, 18, 4, 1, 5, 2);
$chunks = array_chunk($arr, 3);
$ids = array();
foreach ($chunks as $k => $v) {
$otherIds = array(6, 7, 22, 31, 44, 9, 17);
$ids = $v;
foreach ($chunks as $key => $val) {
if ($key <= $k) continue;
foreach ($chunks[$key] as $g => $ch) {
foreach ($otherIds as $o) {
if ($ch['id'] == $o) {
$ids[] = $o;
unset($chunks[$key][$g]);
}
}
}
}
}
As You can see I use a lot of foreaches, but I cant see better solution...
Also, every next iteration of main foreach should be (as mentioned above) shortened by deleted elements from $otherIds - which I this code is NOT doing.
How to achieve it? Is there easier/better/more efficient solution?
I repeat: main goal is to check $otherIds in each iteration of main foreach, and delete same elements from $arr in other chunks.
When you modify an array you are iterating in a foreach loop, you mess up internal pointer in the array and things get confused.
Make a copy while picking up the triplets, do not do unset() nor modify the original array. Thanks to the copy-on-write feature in PHP, the copy will be fast and cost effective, even if the elements are big structures, not only numbers.
Try array_diff():
$arr = array(15, 10, 12, 17, 21, 13, 15, 25, 7, 18, 4, 1, 5, 2);
$chunks = array_chunk($arr, 3);
// Build the filtered list into $output
$output = array();
foreach ($chunks as $k => $v) {
$otherIds = array(6, 7, 22, 31, 44, 9, 17);
// array_diff() returns the list of values from $v that are not in $otherIds
$output[$k] = array_diff($v, $otherIds);
}
// Investigate the result
print_r($output);
Update
I re-read the question and I think I eventually understood the logic (which is not described in the sample data). On each iteration it gets a new set of IDs to ignore and removes them from all chunks, starting from the current chunk.
The updated code is:
$arr = array(15, 10, 12, 17, 21, 13, 15, 25, 7, 18, 4, 1, 5, 2);
$chunks = array_chunk($arr, 3);
// $chunks is numerically indexed; we can use for() to iterate it
// (avoid assigning to $v a value that is never used)
$count = count($chunks);
for ($k = 0; $k < $count; $k ++) {
$otherIds = array(6, 7, 22, 31, 44, 9, 17);
// $chunks is numerically indexed; start with key `$k` to iterate it
for ($key = $k; $key < $count; $key ++) {
// remove the values from $otherId present in the chunk
$chunks[$key] = array_diff($chunks[$key], $otherIds);
}
}
Related
I have a sorted array with these stop_ids.
1,
6,
13,
18,
31,
I just want to find given first search value(6) is before the second given value(31). I tried something like this. That means the find order should be, first (6) then (13) not (13) first and (6) then.
foreach ($parent_array as $key => $value) {
$k = $key;
sort($routes); //another array with above values(stop_ids)
$st = 0;
foreach ($routes as $key => $value) {
if($st == 1){
unset($parent_array[$k]);
break;
}
elseif($value->stop_id == 31){
$st = 1;
continue;
}
}
}
return $parent_array;
I can provide two values. Here I used second value(31) only. Any help ???
Get array keys, under which is every number is located and compare this keys:
function firstNumberFirst($array, $first_number, $second_number)
{
return array_search($first_number, $array) < array_search($second_number, $array);
}
$a = [1, 6, 13, 18, 31];
var_dump(
firstNumberFirst($a, 6, 13),
firstNumberFirst($a, 6, 18),
firstNumberFirst($a, 13, 6)
);
If array is not zero-indexed - apply array_values first.
I have an php array that that i would like split to up into smaller chunks using a loop.
Once all elements with the same values have been pushed into the chunk, i want to use that chunk for something, then continue the loop and setup the next chunk, until all content of the original $array has been used.
public function adjust($array){
// $array = [1, 1, 2, 2, 8, 8, 8, 9, 20]
$chunk = array()
for ($i = 0; $i < sizeof($array); $i++){
// code here
// result should be $chunk = [1, 1]
// use $chunk for something, reset its contents,
// continue loop until chunk is [2, 2],
// rinse and repeat
}
}
I dont necesarrily need a loop, i just require to be able to slice $array into 5 $chunks (for this specific example), to be able to process the data.
Is there an easier way to solve this without a bunch of if/else clauses ?
Initialize $chunk to an array containing the first element. Then loop through the rest of the array, comparing the current element to what's in $chunk. If it's different, process $chunk and reset it.
$chunk = array[$array[0]];
for ($i = 1; $i < count($array); $i++) {
if ($array[$i] != $chunk[0]) {
// use $chunk for something
$chunk = array($array[$i]);
} else {
$chunk[] = $array[$i];
}
}
// process the last $chunk here when loop is done
array_count_values is more or likely what you want.
$array = [1, 1, 2, 2, 8, 8, 8, 9, 20];
foreach (array_count_values($array) as $val => $count) {
$chunk = array_fill(0, $count, $val); // contains [1, 1], [2, 2], etc.
}
This can be done without any conditions and without pre-grouping with array_count_values(). No iterated function calls are necessary. Just use each value as a temporary grouping key as you push each value into their own dedicated subarray. This technique will group values even if recurring values are not consecutive. If you want to remove the temporary keys, just call array_values().
Language Construct Loop: (Demo)
$result = [];
foreach ($array as $value) {
$result[$value][] = $value;
}
var_export(array_values($result));
Functional Loop: (Demo)
var_export(
array_values(
array_reduce(
$array,
function($result, $value) {
$result[$value][] = $value;
return $result;
},
[]
)
)
);
Both output the following data structure:
[[1, 1], [2, 2], [8, 8, 8], [9], [20]]
Is there a way to slice 2d array when all column are all zeros? TIA
$cars = array(
array('Cars', 0, 18, 2, 4, 0, 3, 0, 8),
array('BMW', 0, 13, 2, 4, 0, 3, 0, 8),
array('Saab', 0, 29, 2, 4, 0, 3, 0, 8),
array('Land Rover', 0, 15, 2, 4, 0, 3, 0, 8),
);
echo '<table border="1">';
foreach ($cars as $car) {
echo '<tr>';
foreach ($car as $key) {
echo '<td>'.$key.'</td>';
}
echo '</tr>';
}
echo '</table>';
The following code will remove the columns if every value in the column has the value 0. If you had other plans such as slicing you still can use the code to help you identify what you want.
I do this before actually printing out the array as I do not simply know of a function to do this, so you'd have to create one.
The function array_column() is used to retrieve the columns and I compare it against array_intersect() that returns the rows with the same value and compare that against the amount of rows in your table.
$cols = count($cars[0]);
$rows = count($cars);
$filter = [0]; // add more unwanted values if you please
for($col=1; $col<$cols; $col++){ // skip index 0
if(count(array_intersect(array_column($cars, $col), $filter))) == $rows){
// We found a column "$col" where every value is "0".
foreach($cars as $k => $arr){
// Looping over the main array.
unset($arr[$col]); // unset the cloned array.
$cars[$k] = $arr; // update the original array with new value.
}
}
}
Now you can print your table with the same code you had.
The values in this array are inserted by pulling XML values (using the simplexml_load_file method) and a foreach loop.
$skuArray(2, 4, 3, 7, 7, 4, 1, 7, 9);
After populating the array, I then need to check to see if any duplicate values exist in the array (IE, 7 and 4 in this case). Product->sku contains the skuArray value (from an XML file) in the foreach loop below. The code below isn't working. Any advice? Thanks!
foreach($XMLproducts->product as $Product) {
if (in_array($Product->sku, $skuArray, > 1) {
// execute code
}
}
Use array_count_values() to get the number of times a value occurs and then check to see if it is more than one
$skuArray = array(2, 4, 3, 7, 7, 4, 1, 7, 9);
$dupes = array_count_values($skuArray);
foreach($XMLproducts->product as $Product) {
if ($dupes[$Product->sku] > 1) {
// execute code
}
}
If you need to remove the duplicates then you can use array_unique:
<?php
$input = array(4, 4, 3, 4, 3, 3);
$result = array_unique($input);
// $result = array(4, 3)
?>
If you need only check if there are duplicates then you can do it using array_count_values:
<?php
$input = array(2, 4, 3, 7, 7, 4, 1, 7, 9);
$counts = array_count_values($input);
$duplicates = array();
foreach($counts as $v => $count){
if($count > 1)
$duplicates[] = $v;
}
Then you will have an array $duplicates with the duplicated values.
Source: Php check duplicate values in an array
Your code has typo:
if (in_array($Product->sku, $skuArray, > 1) {
in_array expect the first parameter the needle, but you mentioned "Product->sku contains the skuArray value ", anyway, it should be like this:
if (in_array($Product->sku, $skuArray)) {
In a PHP project I have some data I want to sort using a linear time, simple counting sort:
$ar = array(7, 2, 0, 3, 8, 0, 12, 7, 6, 7);
$count = array();
foreach ($ar as $v)
$count[$v]++;
$sorted = array();
foreach ($count as $v => $c)
for ($i = 0; $i < $c; $i++)
$sorted[] = $v;
The problem is that the above obviously doesn't work. The php array works more like a hashmap than an array. The code can be made to work by inserting ksort($count) before the final loop, but ksort runs in O(nlogn) which destroys the entire point.
Is there any way to do a linear time sort in php? Perhaps using some paramter to array(), or some entirely different structure?
You didn't follow the algorithm correctly. This is O(n).
$ar = array(7, 2, 0, 3, 8, 0, 12, 7, 6, 7);
$count = array();
foreach ($ar as $v) {
$count[$v] = isset($count[$v]) ? $count[$v] + 1 : 1;
}
$sorted = array();
$min = min($ar);
$max = max($ar);
for ($i=$min; $i<=$max; $i++) {
if (isset($count[$i])) {
for ($j=0; $j<$count[$i]; $j++) {
$sorted[] = $i;
}
}
}
also, see array_count_values(), or alternatively compute the min and max inside the counting loop.
Approved answer is wrong. Correct:
$ar = array(7, 2, 0, 3, 8, 0, 12, 7, 6, 7);
$count = array();
foreach ($ar as $v) {
$count[$v] = isset($count[$v]) ? $count[$v] + 1 : 1;
}
$sorted = array();
$min = min($ar);
$max = max($ar);
for ($i=$min; $i <= $max; $i++) {
if (isset($count[$i])) {
for ($j=0; $j<$count[$i]; $j++) {
$sorted[] = $i;
}
}
}
If i understand your question AND comment correctly, just using sort($count) would work no?
$ar = array(7, 2, 0, 3, 8, 0, 12, 7, 6, 7);
$sorted = $ar;
sort($sorted);
var_dump($ar);
var_dump($sorted);
Result:
array(7,2,0,3,8,0,12,7,6,7);
array(0,0,2,3,6,7,7,7,8,12);
But i'm wondering what the foreach($ar as $v)$count[$v]++; does... doesn't really make sense...
Adding some comments to the code to show you why this doesn't do what you think it should do.
$ar = array(7, 2, 0, 3, 8, 0, 12, 7, 6, 7);
$count = array();
foreach ($ar as $v) {
// add each number in $ar to $count.
// the first number in $ar is 7, so 7 will be the first number in $count.
// because 7 is in $ar 3 times, $count[7] == 3.
$count[$v]++;
}
// the output of print_r will be very revealing:
print_r($count);
/*Array
(
[7] => 3
[2] => 1
[0] => 2
[3] => 1
[8] => 1
[12] => 1
[6] => 1
)*/
$sorted = array();
foreach ($count as $v => $c) {
// the first entry: $count[7] == 3
// so add 7 to $sorted 3 times.
// the second entry: $count[2] == 1
// so add 2 to $sorted 1 time.
// etc.
for ($i = 0; $i < $c; $i++) {
$sorted[] = $v;
}
}
This simply groups numbers together based on their location in the first array.
To get the sorted $ar in a variable of it's own ($sorted), it's pretty trivial:
$sorted = $ar;
sort($sorted);
Which makes me think that your question and comment is not giving the whole picture.
Edit: Now after you have clarified that you wanted to implement a specific algorithm (and you actually got an answer already that shows some points that were wrong implementing it first), I think it's worth to focus on another aspect of your question:
You're comparing the complexity of two (theoretical) algorithms, but you're leaving aside how the algorithms are implemented.
PHP's sort() - even based on "bad" quicksort, will outrun your own PHP usercode implementation of some other algorithm by numbers.
You just have compared the wrong parameters here. The complexity of a function does not says much when you compare a build-in PHP function with some function in your user-code.
$A = [1, 2, 2, 2, 1, 3, 3, 1, 2, 4, 5, 0, 0]; // example array
$m = max($A);
$count = array_fill(0, $m + 1, '0');
foreach ($A as $value) $count[$value] += 1;
// next step is print the numbers
$a = [];
foreach ($count as $key => $value) {
for ($i = 0; $i < $value;) {
array_push($a, $key);;
$i++;
}
}
var_dump($count); // print the sorted array
var_dump($a); // print the numbers (low to high)