I have an array that has 120~ or so offsets and I was wondering how you would delete all the values of said array after a certain offset containing a specified string. For example: Offset [68] has the string 'Overflow'. I want to remove everything including 68 and beyond and rebuild the array (with its current sorting in tact).
I tried messing around with slice and splice but I can't seem to get it to return the right values. I was also thinking of just grabbing the offset number that contains 'Overflow' and then looping it through a for statement until $i = count($array); but that seems a little more intensive than it should be.
Would this be the best way? Or is there some function to do this that I'm just using wrong?
Use array_slice().
$desired = array_slice($input, 0, $upTo);
First you need to find the string occurrence in the array, and, if the value was found, trim the array from that point;
function removeString($string, $array)
{
# search for '$string' in the array
$found = array_search($string, $array);
if ($found === false) return $array; # found nothing
# return sliced array
return array_slice($array, $found);
}
And if you need to make the array sequential (to avoid surprises due to missing offsets), you can always add in the first line $array = array_values($array). This will reorganize the array values in a new array with ordered offsets: 0, 1, 2, 3, 4...
Related
The following is the code
<?php
$id ="202883-202882-202884-0";
$str = implode('-',array_unique(explode('-', $id)));
echo $str;
?>
The result is
202883-202882-202884-0
for $id ="202883-202882-202882-0";, result is 202883-202882-0
I would like to replace the duplicate value with zero, so that the result should be like 202883-202882-0-0, not just remove it.
and for $id ="202883-0-0-0";, result should be 202883-0-0-0. zero should not be replaced, repeating zeros are allowed.
How can I archive that?
More info:
I want to replace every duplicate numbers. Because this is for a product comparison website. There will be only maximum 4 numbers. each will be either a 6 digit number or single digit zero. all zero means no product was selected. one 6 digit number and 3 zero means, one product selected and 3 blank.
Each 6 digit number will collect data from database, I dont want to allow users to enter same number multiple times (will happen only if the number is add with the URL manually.).
Update: I understand that my question was not clear, may be my English is poor.
Here is more explanation, this function is for a smartphone comparison website.
The URL format is sitename.com/compare.html?id=202883-202882-202889-202888.
All three numbers are different smartphones(their database product ID).
I dont want to let users to type in the same product ID like id=202883-202882-202882-202888. It will not display two 202882 results in the website, but it will cause some small issues. The URL will be same without change, but the internal PHP code should consider it as id=202883-202882-202888-0.
The duplicates should be replaced as zero and added to the end.
There will be only 4 numbers separated by "-".
The following examples might clear the cloud!
if pid=202883-202882-202889-202888 the result should be 202883-202882-202889-202888
if pid=202883-202883-202883-202888 the result should be 202888-0-0-0
if pid=202883-202882-202883-202888 the result should be 202883-202882-202888-0
if pid=202882-202882-202882-202882 the result should be 202882-0-0-0
I want to allow only either 6 digit numbers or single digit zero through the string.
if pid=rgfsdg-fgsdfr4354-202883-0 the result should be 202883-0-0-0
if pid=fasdfasd-asdfads-adsfds-dasfad the result should be 0-0-0-0
if pid=4354-45882-445202882-202882 the result should be 202882-0-0-0
It is too complicated for me create, I know there are bright minds out there who can do it much more efficiently than I can.
You can do a array_unique (preserves key), then fill the gaps with 0. Sort by key and you are done :)
+ on arrays will unify the arrays but prioritizes the one on the left.
Code
$input = "0-1-1-3-1-1-3-5-0";
$array = explode('-', $input);
$result = array_unique($array) + array_fill(0, count($array), 0);
ksort($result);
var_dump(implode('-',$result));
Code (v2 - suggested by mickmackusa) - shorter and easier to understand
Fill an array of the size of the input array. And replace by leftover values from array_unique. No ksort needed. 0s will be replaced at the preserved keys of array_unique.
$input = "0-1-1-3-1-1-3-5-0";
$array = explode('-', $input);
$result = array_replace(array_fill(0, count($array), 0), array_unique($array));
var_export($result);
Working example.
Output
string(17) "0-1-0-3-0-0-0-5-0"
Working example.
references
ksort - sort by key
array_fill - generate an array filled with 0 of a certain length
This is another way to do it.
$id = "202883-202882-202882-0-234567-2-2-45435";
From the String you explode the string into an array based on the delimiter which in this case is '-'/
$id_array = explode('-', $id);
Then we can loop through the array and for every unique entry we find, we can store it in another array. Thus we are building an array as we search through the array.
$id_array_temp = [];
// Loop through the array
foreach ($id_array as $value) {
if ( in_array($value, $id_array_temp)) {
// If the entry exists, replace it with a 0
$id_array_temp[] = 0;
} else {
// If the entry does not exist, save the value so we can inspect it on the next loop.
$id_array_temp[] = $value;
}
}
At the end of this operation we will have an array of unique values with any duplicates replaced with a 0.
To recreate the string, we can use implode...
$str = implode('-', $id_array_temp);
echo $str;
Refactoring this, using a ternary to replace the If,else...
$id_array = explode('-', $id);
$id_array_temp = [];
foreach ($id_array as $value) {
$id_array_temp[] = in_array($value, $id_array_temp) ? 0 : $value;
}
$str = implode('-', $id_array_temp);
echo $str;
Output is
202883-202882-0-0-234567-2-0-45435
This appears to be a classic XY Problem.
The essential actions only need to be:
Separate the substrings in the hyphen delimited string.
Validate that the characters in each substring are in the correct format AND are unique to the set.
Only take meaningful action on qualifying value.
You see, there is no benefit to replacing/sanitizing anything when you only really need to validate the input data. Adding zeros to your input just creates more work later.
In short, you should use a direct approach similar to this flow:
if (!empty($_GET['id'])) {
$ids = array_unique(explode('-', $_GET['id']));
foreach ($ids as $id) {
if (ctype_digit($id) && strlen($id) === 6) {
// or: if (preg_match('~^\d{6}$~', $id)) {
takeYourNecessaryAction($id);
}
}
}
I have a form that submits an array of user roles for processing by the server. Here is an example of the $data['roles'] posted by the form:
Array ( [0] => 5 [1] => 16 )
I want to check if $data['roles'] contains either one of the values 16, 17, 18 or 19. As you can see in the example it contains 16. in_array seems like the logical choice here, but passing an array of values as the needle of in_array doesn't work:
$special_values = array(16, 17, 18, 19);
if (in_array($special_values, $data['roles'])) {
// this returns false
}
Neither does passing the exact same values in an array:
$special_values = array(5, 16);
if (in_array($special_values, $data['roles'])) {
// this also returns false
}
Also, switching places between the two arrays as needle and haystack doesn't change the result. If I just ask if 16 is in the array, it works fine:
$special_value = 16;
if (in_array($special_value, $data['roles'])) {
// this returns true
}
The documentation gives examples of using arrays as needles, however it seems the structure needs to be exactly the same in the haystack for it to return true. But then I don't get why my second example doesn't work. I'm obviously doing something wrong or missing something here.
What is the best way to check if any of the values in one array exists in another array?
Edit: This question (possible duplicate) is not asking the same thing. I want to match any value in one array against any value in another. The linked question wants to match all values in one array against the values of another.
This may help you
Using array_intersect()
$result = array_intersect($data['roles'], array(16, 17, 18, 19));
print_r($result);
Using in_array()
$result = false;
foreach ($special_values as $val) {
if (in_array($val, $data['roles'], true)) {
$result = true;
}
}
The bet way is to use array_diff and empty functions, I think:
if ( ! empty(array_diff($special_values, $data['roles']))) {
throw new Exception('Some of special values are not in data roles');
}
or array_intersect if you want to return values which occur in both arrays.
I'm not sure the title really gets across what I'm asking, so here's what I'm trying to do:
I have an array of arrays with four integer elements each, ie.
Array(Array(1,2,3,4), Array(4,2,3,1), Array(18,3,22,9), Array(23, 12, 33, 55))
I basically need to remove one of the two arrays that have the same values in any order, like indices 0 and 1 in the example above.
I can do this pretty easily when there are only two elements to check, using the best answer code in this question.
My multidimensional array can have 1-10 arrays at any given time, so I can't seem to figure out the best way to process a structure like that and remove arrays that have the same numbers in any order.
Thanks so much!
I've been thinking about this, and I think using a well designed closure with array_filter might be the way I'd go about this:
$matches = array();
$array = array_filter($array, function($ar) use (&$matches) {
sort($ar);
if(in_array($ar, $matches)) {
return false;
}
$matches[] = $ar;
return true;
});
See here for an example: http://ideone.com/Zl7tlR
Edit: $array will be your final result, ignore $matches as it's just used during the filter closure.
How to I get an array of the last n items of another array in PHP?
$n is equal to the number of items you want off the end.
$arr = array_slice($old_arr, -$n);
You can use array_slice:
$arr = array_slice($old_arr, -$n, $n, true);
If the array indices are meaningful to you, remember that array_slice will reset and reorder the numeric array indices. You need the preserve_keys flag (4th parameter) set to true to avoid this.
I a string that is coming from my database table say $needle.
If te needle is not in my array, then I want to add it to my array.
If it IS in my array then so long as it is in only twice, then I still
want to add it to my array (so three times will be the maximum)
In order to check to see is if $needle is in my $haystack array, do I
need to loop through the array with strpos() or is there a quicker method ?
There are many needles in the table so I start by looping through
the select result.
This is the schematic of what I am trying to do...
$haystack = array();
while( $row = mysql_fetch_assoc($result)) {
$needle = $row['data'];
$num = no. of times $needle is in $haystack // $haystack is an array
if ($num < 3 ) {
$$haystack[] = $needle; // hopfully this adds the needle
}
} // end while. Get next needle.
Does anyone know how do I do this bit:
$num = no. of times $needle is in $haystack
thanks
You can use array_count_values() to first generate a map containing the frequency for each value, and then only increment the value if the value count in the map was < 3, for instance:
$original_values_count = array_count_values($values);
foreach ($values as $value)
if ($original_values_count[$value] < 3)
$values[] = $value;
As looping cannot be completely avoided, I'd say it's a good idea to opt for using a native PHP function in terms of speed, compared to looping all values manually.
Did you mean array_count_values() to return the occurrences of all the unique values?
<?php
$a=array("Cat","Dog","Horse","Dog");
print_r(array_count_values($a));
?>
The output of the code above will be:
Array (
[Cat] => 1,
[Dog] => 2,
[Horse] => 1
)
There is also array_map() function, which applies given function to every element of array.
Maybe something like the following? Just changing Miek's code a little.
$haystack_count = array_count_values($haystack);
if ($haystack_count[$needle] < 3)
$haystack[] = $needle;