Remove zeros that follow a 1 in an array - php

I am getting the values of an array of checkboxes (created dynamically). There were several issues, but I narrowed it to a certain point. Now the abstract of the problem is this (forget for a second these are checkboxes and just imagine we are working with an array of numbers).
I have an array store[20] which contains values of 0s or 1s.
I need to get rid of every 0 that follows a one.
Ex. lets assume my array is store={0, 1, 0, 1, 0, 0}.
I need to create a new array that will be like this check={0, 1, 1, 0}.
The third and fifth terms dont have to be inserted in the new array because they follow the second and fourth term (which are ones).
Also, in case you wonder, there are no occurrences of two consecutive ones, so no need to worry about that.
Here is my php code (but implementations in other languages are the same since its just for loops and arrays):
$j=0; $count=0;
for($j=0;$j<20; $j++) {
$check[$j] = $store[$j + $count];
if($store[$j]) {
$count = $count + 1;
}
}
The code is not working correctly. Maybe I am dead wrong in the way im implementing it. But Im a bit tired and started seeing things. I really can't see what im doing wrong.
PS: I didnt include the array declarations and other preceding code because i already tested it and I know they are ok. The problem is in the logic of this part of the code.

In PHP you could just use str_split, a little regex and an implode without having to worry about a for loop. Adding in array_map, the results will be returned as integers instead of strings.
$check = array_map('intval',str_split('',preg_replace('/01/','',implode('',$store))));
Demo:
<?php
$store = array(0, 1, 0, 1, 0, 0);
$check = str_split(preg_replace('/10/','1',implode('',$store)));
var_dump($check);
$check = array_map('intval',$check)
var_dump($check);
?>

This is the output I get from running your code:
Array
(
[0] => 0
[1] => 1
[2] => 1
[3] => 0
[4] =>
[5] =>
[6] =>
[7] =>
[8] =>
[9] =>
[10] =>
[11] =>
[12] =>
[13] =>
[14] =>
[15] =>
[16] =>
[17] =>
[18] =>
[19] =>
)
So basically it's working, except for the presence of null values at the end of your array since you're reading values outside of the bounds of the $store array. Simply check whether you're outside of the bounds of the array in your for loop. Notice I added +$count to the operation.
$store = array(0, 1, 0, 1, 0, 0);
$j=0;
$count=0;
$check = array();
for($j=0;$j+$count<count($store); $j++) {
$check[] = $store[$j + $count];
if($store[$j+$count]) {
$count = $count + 1;
}
}
Output:
Array
(
[0] => 0
[1] => 1
[2] => 1
[3] => 0
)

As I understood the question you just need the preceeding element to decide whether a 0 is included in the result or not:
<?php
$store=[0, 1, 0, 1, 0, 0];
$prev=0; $result = array();
foreach($store as $e) {
if ( $e || !$prev ) {
$result[] = $e;
}
$prev = $e;
}
var_export($result);
...there's most likely a more elegant solution but this one prints
array (
0 => 0,
1 => 1,
2 => 1,
3 => 0,
)

Related

How can I combine multiple values into a single value in an array?

I have this array:
$dataArr = Array(
[0] => Repper
[1] => Pavel
[2] => 7.1.1970
[3] => K.H.Máchy //start of address
[4] => 1203/2,
[5] => Bruntál // end of address
[6] => EM092884
[7] => 7.1.2019
);
I need to modify this array so that the address (index 3 to index 6) is below index 3, but indexes 4 and 5 will be removed. Thus, the newly modified array will have indexes from 0 to 5 (6 values). The number of values ​​from index 3 (from the beginning of the address) may be even greater and the address may end, for example, with index number 9. But the beginning of the address is always from index 3.
Expected result:
$dataArr= Array(
[0] => Repper
[1] => Pavel
[2] => 7.1.1970
[3] => K.H.Máchy 1203/2, Bruntál
[4] => EM092884
[5] => 7.1.2019
);
My idea was as follows. I try something like this:
I go through the matrix from index 3 and look for a regular match (the value just after the end of the address). Until the array value matches the regex, I compile the values ​​into string.
$address = NULL; //empty variable for address from $dataArr
foreach($dataArr as $k => $val) {
if($k >= 3) {
if(! preg_match('/^\[A-Za-z]{2}\d{6}/', $val)) {
$address .= $val;
//Then put this variable $address in position $dataArr[3]
}
}
}
But it seems that the 'if' condition with preg_match is still true. I need the foreach cycle to stop before index 6, but the cycle is still working, to last value of array. Where's the mistake? This problem hinders me in completing the script. Thank you very much.
One other possibility, pop off the beginning and end
$first = array_splice($dataArr, 0, 3);
$last = array_splice($dataArr, -2);
Then implode the remaining part and put it all back together.
$dataArr = array_merge($first, [implode(' ', $dataArr)], $last);
// or in PHP 7.4
$dataArr = [...$first, implode(' ', $dataArr), ...$last];
This should work regardless of the size of the address, but it does totally depend on the last two elements after the address always being present, so if there's any way those would be missing sometimes you'll need something a little more complicated to account for that.
Why overcomplicate things with regexp and loops? Just literally do what you describe: if your address runs from n to m, take the array slice from n to m, implode that to a string, set array[n] to that string, and then remove fields [n+1...m] from your array:
function collapse_address($arr, $start, $end) {
$len = $end - $start;
// collapse the address:
$arr[$start] = join(" ", array_slice($arr, $start, $len));
// remove the now-duplicate fields:
array_splice($arr, $start + 1, $len - 1);
// and we're done.
return $arr;
}
$arr = Array(
'Repper',
'Pavel',
'7.1.1970',
'K.H.Máchy', //start of address
'1203/2',
'Bruntál', // end of address
'EM092884',
'7.1.2019'
);
$arr = collapse_address($arr, 3, 6);
result:
Array
(
[0] => Repper
[1] => Pavel
[2] => 7.1.1970
[3] => K.H.Máchy 1203/2 Bruntál
[4] => EM092884
[5] => 7.1.2019
)
Of course, you might not want $end to be exclusive, but that's up to you.

PHP Regex removing unwanted values from pattern

I have a large array of scraped names and prices similar to the following:
Array([0] => apple3 [1] => £0.40 [2] => banana6 [3] => £1.80 [4] => lemon [5] => grape [6] => pear5 [7] => melon4 [8] => £2.32 [9] => kiwi [10] => £0.50)
I would like to remove the fruit names that are not immediately followed by a price. In the above example this would remove: [4] => lemon [5] => grape [6] => pear5 resulting in the following output:
Array([0] => apple3 [1] => £0.40 [2] => banana6 [3] => £1.80 [7] => melon4 [8] => £2.32 [9] => kiwi [10] => £0.50)
If the array needs to be converted to a string in order for me to do this that is not a problem, nor is adding values between the array items in order to aid with regex searches. I have so far been unable to find the correct regular expression to do this using preg_match and preg_replace.
The most important factor is the need to maintain the sequential order of the fruits and prices in order for me at a later stage to convert this into an associative array of fruits and prices.
Thanks in advance.
Why involve regular expressions? This is doable with a simple foreach loop wherein you iterate over the array and remove names that follow names:
$lastWasPrice = true; // was the last item a price?
foreach ($array as $k => $v) {
if (ctype_alpha($v)) {
// it's a name
if (!$lastWasPrice) {
unset($array[$k]); // name follows name; remove the second
}
$lastWasPrice = false;
}
else {
// it's a price
$lastWasPrice = true;
}
}
The following code does both of your tasks at once: getting rid of the fruit without value and turning the result into an associative array of fruits with prices.
$arr = array('apple', '£0.40', 'banana', '£1.80', 'lemon', 'grape', 'pear', 'melon', '£2.32', 'kiwi', '£0.50' );
preg_match_all( '/#?([^£][^#]+)#(£\d+\.\d{2})#?/', implode( '#', $arr ), $pairs );
$final = array_combine( $pairs[1], $pairs[2] );
print_r( $final );
First, the array is converted to a string, separated by '#'. The regex captures all groups of fruits with prices - each stored as a separate subgroup in the result. Combining them into an associative array is a single function call.
Something like this might help you
$array = ...;
$index = 0;
while (isset($array[$index + 1])) {
if (!is_fruit($array[$index + 1])) {
// Not followed by a fruit, continue to next pair
$index += 2;
} else {
unset($array[$index]); // Will maintain indices in array
$index += 1;
}
}
Not tested though. Also, you need to create the function is_fruit yourself ;)
Without reformatting it, I don't think you can do it with preg_match or preg_replace-- maybe, but nothing is coming to mind.
What is creating that array? If possible, I would alter it to look more like:
Array([apple] => £0.40 [banana] => £1.80 [lemon] => [grape] => '' [pear ] => '' [melon => £2.32 [kiwi] => £0.50)
Then array_filter($array) is all you'd need to clean it up. If you can't alter the way the original array is created I'd lean towards creating key/value array out of the original.
Try replacing the pattern ** => ([a-zA-Z])** with ** => £0.00 $1**
Basically searching for the context where there is null price and inserting zero pounds.
Hope this helps.
Good luck
Simply do this :
<?php
for($i=0;$i<count($my_array);$i++)
{
if($my_array[$i+1]value=="")
unset($my_array[$i])
}
?>
assume $a is your array.
function isPrice($str) {
return (substr($str, 0, 1) == '£');
}
$newA = array();
for($i=0;$i<count($a);$i++) {
if( isPrice($a[$i]) != isPrice($a[$i+1]) ){
$newA[] = $a[$i];
}
}

How to remove ALL duplicate values from an array in PHP?

I want to check only the value [id] for duplicates, and remove all keys where this "field" [id] is a duplicate.
Example: If I have numbers 1,2,1. I want the result to be 2, not 1,2. And criteria for duplicates is determined only by checking [id], not any other "field".
Original array:
Array
(
[0] => Array
(
[name] => John
[id] => 123
[color] => red
)
[1] => Array
(
[name] => Paul
[id] => 958
[color] => red
)
[2] => Array
(
[name] => Jennifer
[id] => 123
[color] => yellow
)
)
The result I want:
Array
(
[0] => Array
(
[name] => Paul
[id] => 958
[color] => red
)
)
I agree with everyone above, you should give us more information about what you've tried, but I like to code golf, so here's a completely unreadble solution:
$new_array = array_filter($array, function($item) use (&$array){
return count(array_filter($array, function($node) use (&$item){
return $node['id'] == $item['id'];
})) < 2;
});
This should be fairly easy to accomplish with a couple of simple loops:
set_time_limit(0); // Disable time limit to allow enough time to process a large dataset
// $items contains your data
$id_counts = array();
foreach ($items as $item) {
if (array_key_exists($item['id'], $id_counts)) {
$id_counts[$item['id']]++;
} else {
$id_counts[$item['id']] = 1;
}
}
for ($i = count($items); $i >= 0; $i--) {
if ($id_counts[$items[$i]['id']] > 1) {
array_splice($items, $i, 1);
}
}
Result:
Array
(
[0] => Array
(
[name] => Paul
[id] => 958
[color] => red
)
)
While there are neater ways to do it, one advantage of this method is you're only creating new arrays for the list of ids and duplicate ids and the array_splice is removing the duplicates from the original array, so memory usage is kept to a minimum.
Edit: Fixed a bug that meant it sometimes left one behind
This is a very basic approach to the answer and I am sure there are much better answers however I would probably start by doing it the way I would on paper.
I look at the first index, check its value. Then I go through every other index making note of their index if the value is the same as my originally noted value. Once I have gone through the list if I have more than one index with that particular value I remove them all (starting with the highest index, so as to not affect indexes of the others while deleting).
Do this for all other indexes till you reach the end of the list.
It is long winded but will make sure it removes all values which have duplicates. and leaves only those which originally had no duplicates.
function PickUniques(array $items){
// Quick way out
if(empty($items)) return array();
$counters = array();
// Count occurences
foreach($items as $item){
$item['id'] = intval($item['id']);
if(!isset($counters[$item['id']])){
$counters[$item['id']] = 0;
}
$counters[$item['id']]++;
}
// Pop multiples occurence ones
foreach($counters as $id => $occurences){
if($occurences > 1){
unset($counters[$id]);
}
}
// Keep only those that occur once (in $counters)
$valids = array();
foreach($items as $item){
if(!isset($items[$item['id']])) continue;
$valids[$item['id']] = $item;
}
return $valids;
}
Try this one :)

PHP how to loop through an array and grab specific parts

Ok so im trying to grab a single part of an array, the array is the return for some stats there can be up to 8 players in the server, the data i get is like this
Array (
[0] => 1
[1] => Player1
[2] =>
[3] => 1
[4] => 0
[5] => 0
[6] => 0
[7] => 0
[8] => 1
[9] => Player2
[10] =>
[11] => 1
[12] => 0
[13] => 0
[14] => 0
[15] => 0
)
so that is the return for 2 players, as i said it can be up to 8, anyway i am trying to just grab the player names and im not sure how to go about it ( Player1 , Player2 ) is the only data i need, any help is appreciated, it always returns 8 pieces of data per player never more never less if that makes it easier
(sorry for bad english)
If you have control over the return type, I would restructure the array being returned either into an Object or an array of arrays where each sub array contains all of the information for one player.
I you don't have control over the return type and the Player's name is always in the second position within the return array you can use a while loop to iterate over the array. Use a counter starting at 1 and then increment the counter by 8 each time through the loop. For example:
$i= 1;
while ($i < count($return_var)) {
$name = $return_var[$i];
// do something w/ name
$i += 8;
}
You want to get all items that are not '' (assuming empty string), 0 or 1 (assuming integers here):
$playerNames = array_diff($array, array('', 0, 1));
If you more specifically know what the format of the array actually is, you can also create some little "parser":
$playerSize = 8;
$playerFields = array('_1', 'name', '_3', '_4', '_5', '_6', '_7', '_8');
$players = array_chunk($array, $playerSize);
foreach($players as &$player)
{
$player = (object) array_combine($playerFields, $player);
}
unset($player);
This does parse $array into another array $players that contains one object per each player. Each object has the name property now:
printf("%d Player(s):\n", count($players));
foreach($players as $i => $player)
{
printf("#%d: %s\n", $player->name);
}
if the array you pasted is called $array and the values of the places without players are always numeric (like your example), this code will work:
$players = array();
foreach($array as $player){
if(!empty($player) && !is_numeric($player){
$players[]=$player;
}
}
var_dump($players);

If value exists in one PHP array, add value to second array

I have two PHP arrays. One contains a group name and another contains a pay wage value.
$group_wages_array = Array ( [0] => 1 [1] => 4 [2] => 1 [3] => 3 );
This means there are four employees on the schedule. Two are assigned to group 1, another to group 4 and the last to group 3.
The second array is as follows:
$tot_wages_array = Array ( [0] => 500 [1] => 44 [2] => 80 [3] => 11.25 );
This is a sample array of each employee's wage. Both arrays are constructed in order as values are added in a mysql while loop as it pulls the info from the database.
Later on down the line, I combine the two arrays to get one array where the key is the group number and the value is the total wages for that group:
$combined_group_wages = array_combine($group_wages_array, $tot_wages_array);
This works like a charm EXCEPT for when more than one employee is assigned to the same group. These arrays are built in a mysql while loop as it loops through each employee's info:
array_push($tot_wages_array, $totemp_wages_sch); // Add their wage to the array
array_push($group_wages_array, $emp_data['group_id']); // Add their group to the array
Instead of just pushing the data to the array, I need to do this... I know the english but I don't know how to code it:
If $emp_data['group_id'] exists as value in $group_wages_array, add nothing to this array but get the key. Add $totemp_wages_sch to $tot_wages_array where key = group_wages_array key
I know it sounds more like an SQL query but I have to keep the keys and values in order so that they can be combined later in the page. If I can get this to work right, The arrays shown in the example would be:
$group_wages_array = Array ( [0] => 1 [1] => 4 [2] => 3 );
$tot_wages_array = Array ( [0] => 580 [1] => 44 [2] => 11.25 );
$combined_group_wages = array_combine($group_wages_array, $tot_wages_array);
$combined_group_wages = Array ( [1] => 580 [4] => 44 [3] => 11.25 );
...I've got to make this work using PHP. Any ideas?
I came up with a solution based on a combination of two of the answers submitted below. Here it is if it can help someone:
if(in_array($emp_data['group_id'], $group_wages_array)){
$key = key($group_wages_array);
$tot_wages_array[$key] += $totemp_wages_sch;
} else {
array_push($group_wages_array, $emp_data['group_id']);
array_push($tot_wages_array, $totemp_wages_sch);
}
This should do it:
$group_wages_array = array(1, 4, 1, 3);
$tot_wages_array = array(500, 44, 80, 11.25);
$combined_group_wages = array();
for ($i=0; $i<count($group_wages_array); $i++) {
$group = $group_wages_array[$i];
if (array_key_exists($group_wages_array[$group], $combined_group_wages)) {
$combined_group_wages[$group] += $tot_wages_array[$i];
} else {
$combined_group_wages[$group] = $tot_wages_array[$i];
}
}
print_r($combined_group_wages);
Yields:
Array
(
[1] => 580
[4] => 44
[3] => 11.25
)
But I recommend that you just switch to using objects to better represent your data.
If I could see the entirety of the code that would help a lot, but here's your English converted to php. Show me more code and I can perfect it, until then try this ->
if(in_array($emp_data['group_id'], $group_wages_array)){
$key = key($group_wages_array);
$tot_wages_array[$key] = $totemp_wages_sch;
} else {
array_push($group_wages_array, $emp_data['group_id']);
}

Categories