I am simply trying to remove all of the Array objects that have 'visible' set to '0'
Array:
{
"Count":5,
"0":{"id":"1","visible":"0"},
"1":{"id":"3","visible":"0"},
"2":{"id":"1","visible":"0"},
"3":{"id":"2","visible":"0"},
"4":{"id":"3","visible":"0"}
}
PHP:
function cleanup($arr) {
for($i = 0; $i < (count($arr)-1); $i++) {
if($arr[$i]['visible'] == false) {
unset($arr[$i]);
}
}
$newarr = array_unique($arr, SORT_REGULAR);
$newarr['Count'] = count($newarr)-1;
return $newarr;
}
Result:
{
"Count":2,
"3":{"id":"2","visible":"0"},
"4":{"id":"3","visible":"0"}
}
In my mind this should work and return {"Count":0}. Also Why have the 'keys' not been set to 0,1 instead of 3,4. Where am i going wrong?
You are using count($arr)-1) inside the for loop, and it gets re-evaluated every iteration, so after you unset the first three times, i is 3, but count($arr)-1) is 1, and you exit the loop.
You should set $j=count($arr)-1 before the for loop, and use for($i = 0; $i < $j; $i++)
In general it is bad programming practice (performance-wise) to use functions like count() inside the for loop
unset() will not reorder the array indexes if you removing an index from the middle of an numerical array. You need to reindex the array by yourself. array_values() is helpful here.
function cleanup($arr) {
for($i = 0; $i < (count($arr)-1); $i++) {
if($arr[$i]['visible'] == false) {
unset($arr[$i]);
}
}
$newarr = array_values(array_unique($arr, SORT_REGULAR));
return $newarr;
}
The Count property makes no sense for me therefore I dropped it away. You may use the function count() instead.
Related
I want to create an array with x elements, where each element is created by calling a function. I'm looking for an idiomatic way to do this that minimizes state, especially mutating state, and also minimizes imperativeness.
I have working code that does this task, more specifically it creates an array with 10 elements using a function that returns a random character.
array_map(
function() use ( $characters, $characterCount ) {
return $characters[mt_rand( 0, $characterCount - 1 )];
},
array_fill( 0, 10, null )
)
When starting with this I was looking for something like the following, but did not find it:
array_create(
function() {},
10
);
It is common to simply use a looping construct like:
$array = array();
for($i = 0; $i < 10; $i++) {
$array[] = randomfunction();
}
If you want to wrap this in a function, do something like:
function genArray($x, $func) {
$array = array();
for($i = 0; $i < $x; $i++) {
$array[] = $func();
}
return $array;
}
Then you can pass it the number of elements and which function to use!
I am looking for a PHP solution to use a loop to go through to capture all the data
Here is an example of a lookup without using a loop
if (array_key_exists('utf8String', $cert['tbsCertificate']['subject']['rdnSequence'][0][0]['value'])) {
// do somthing
} else if (array_key_exists('printableString', $cert['tbsCertificate']['subject']['rdnSequence'][0][0]['value'])) {
// do somthing
} else if (array_key_exists('bmpString', $cert['tbsCertificate']['subject']['rdnSequence'][0][0]['value'])) {
// do somthing
} else if (array_key_exists('telextexString', $cert['tbsCertificate']['subject']['rdnSequence'][0][0]['value'])) {
// do somthing
}
I need the loop to go through the entire array. For ONLY the first [ ] the loop should increase the integer [0] to 1, [2] and so forth until its gone through the whole lot. In case you are wondering, the second [ ] is always [0] so that needs to remain as is.
Right now I am copying/pasting the above about 20 times and manually updating the number in the first box but I am hoping there is a more elegant way to achieve that.
-- MORE CONTEXT --
-- WORKING CODE -- offered by #Ghost
$count = count($cert['tbsCertificate']['subject']['rdnSequence']);
$exists = array('utf8String', 'printableString', 'teletexString');
$oid = array('id-at-stateOrProvinceName', 'id-at-countryName', 'id-at-localityName', 'id-at-commonName', 'id-at-organizationalUnitName');
for($i = 0; $i < $count; $i++) {
foreach($exists as $field) {
if(array_key_exists($field, $cert['tbsCertificate']['subject']['rdnSequence'][$i][0]['value'])) {
$value = $cert['tbsCertificate']['subject']['rdnSequence'][$i][0]['value'][$field];
echo $value, ' [',$field, ']',"\n";
}
}
}
You can just add another loop inside applying each field into array_key_exists, this applies to #Markus' idea anyway:
$count = count($cert['tbsCertificate']['subject']['rdnSequence']);
$exists = array('utf8String', 'printableString', 'teletexString');
$oid = array('id-at-stateOrProvinceName', 'id-at-countryName', 'id-at-localityName', 'id-at-commonName', 'id-at-organizationalUnitName');
for($i = 0; $i < $count; $i++) {
foreach($exists as $field) {
if(array_key_exists($field, $cert['tbsCertificate']['subject']['rdnSequence'][$i][0]['value'])) {
$value = $cert['tbsCertificate']['subject']['rdnSequence'][$i][0]['value'][$field];
$k = array_keys($cert['tbsCertificate']['subject']['rdnSequence'][$i][0]['type']);
$oid = reset($k);
break;
}
}
}
[ EDIT: Please see the comments below. ] How about for simples...
$strings = ['utf8String', 'printableString' ... ];
foreach ($strings as $string) { // do your checks etc. }
I suppose you know how to increment a counter in a loop. $i++ and stuff, use [$i] wherever you need to increment the reference value in your $cert array. On match, break or continue in place of else if, depending on what exactly you need to accomplish here. Your objectives aren't too clear in the question, could share a bit more insight...
I'm using json_decode to parse JSON files. In a for loop, I attempt to capture specific cases in the JSON in which one element or another exist. I've implemented a function that seems to fit my needs, but I find that I need to use two for loops to get it to catch both of my cases.
I would rather use a single loop, if that's possible, but I'm stuck on how to get both cases caught in a single pass. Here's a mockup of what I would like the result to look like:
<?php
function extract($thisfile){
$test = implode("", file($thisfile));
$obj = json_decode($test, true);
for ($i = 0; $i <= sizeof($obj['patcher']['boxes']); $i ++) {
//this is sometimes found 2nd
if ($obj['patcher']['boxes'][$i]['box']['name'] == "mystring1") {
}
//this is sometimes found 1st
if ($obj['patcher']['boxes'][$i]['box']['name'] == "mystring2") {
}
}
}
?>
Can anyone tell me how I could catch both cases outlined above within a single iteration?
I clearly could not do something like
if ($obj['patcher']['boxes'][$i]['box']['name'] == "string1" && $obj['patcher']['boxes'][$i]['box']['name'] == "string2") {}
...because that condition would never be met.
Generally what I do when I have raw data that is in an order that isn't ideal to work with is to run a first loop pass to generate a a list of indexes for me to pass through a second time.
So a quick example from your code:
<?php
function extract($thisfile){
$test = implode("", file($thisfile));
$obj = json_decode($test, true);
$index_mystring2 = array(); //Your list of indexes for the second condition
//1st loop.
$box_name;
for ($i = 0; $i <= sizeof($obj['patcher']['boxes']); $i ++) {
$box_name = $obj['patcher']['boxes'][$i]['box']['name'];
if ( $box_name == "mystring1") {
//Do your code here for condition 1
}
if ($box_name == "mystring2") {
//We push the index onto an array for a later loop.
array_push($index_mystring2, $i);
}
}
//2nd loop
for($j=0; $j<=sizeof($index_mystring2); $j++) {
//Your code here. do note that $obj['patcher']['boxes'][$j]
// will refer you to the data in your decoded json tree
}
}
?>
Granted you can do this in more generic ways so it's cleaner (ie, generate both the first and second conditions into indexes) but i think you get the idea :)
I found that something like what #Jon had mentioned is probably the best way to attack this problem, for me at least:
<?php
function extract($thisfile){
$test = implode("", file($thisfile));
$obj = json_decode($test, true);
$found1 = $found2 = false;
for ($i = 0; $i <= sizeof($obj['patcher']['boxes']); $i ++) {
//this is sometimes found 2nd
if ($obj['patcher']['boxes'][$i]['box']['name'] == "mystring1") {
$found1 = true;
}
//this is sometimes found 1st
if ($obj['patcher']['boxes'][$i]['box']['name'] == "mystring2") {
$found2 = true;
}
if ($found1 && $found2){
break;
}
}
}
?>
I have an array $num_arr ,so I want get a new array that It's sum is smaller than 10,so i write the code like this,
$num_arr=array(1,3,6,5,4,2,7,9,5,3,6,2,4,7);
$sum=0;
for($i=0;$i<=count($num_arr);$i++){
$sum+=$num_arr[$i];
$k++;
if($sum>=10){
$need_arr[]=array_slice($num_arr,0,$k);
array_splice($num_arr,0, $k);
$k=0;
$sum=0;
}
}
The result $need_arr is not right,that is why and how can get the right array like this: array(array(1,3,6),array(5,4),array(2,7),array(9),...)?
Implemented a "oneliner" just for fun:
$num_arr=array(1,3,6,5,4,2,7,9,5,3,6,2,4,7);
$result = array_reduce($num_arr, function($result, $curr) {
if (!count($result)) {
$result[] = array();
}
$last =& $result[count($result) - 1];
if (array_sum($last) + $curr > 10) {
$result[] = array($curr);
} else {
$last[] = $curr;
}
return $result;
}, array());
var_dump($result);
Online demo: http://ideone.com/aFVmkp
Among other things, you are changing the length of the array when you use array_splice, but you aren't adjusting $i in any way.
In fact, you can remove that array_splice line entirely, since you're continuing to iterate over the array.
Also, you're only starting a new array if you're over 10. You should change your condition to this:
if(!isset($num_arr[$i+1]) || $sum+$num_arr[$i+1] >= 10)
I have an array:
$array=array('key1'=>'value1','key2'=>'value2','value3');
and a foreach:
foreach($array as $v){
//do something
}
Is there a way to know in the foreach which element we are parsing?
(without doing something like:)
$count=0;
foreach($array as $v){
$count++;
// do something
}
thanks
EDIT1:
Sorry maybe I was not clear:
I don't want know the key, but I need to know how many elements are left in the foreach. (that's why I did the example with $count)
You could use a class that extends ArrayIterator:
class FooArrayIterator extends ArrayIterator {
private $offset = 0;
public function next() {
$this->offset++;
return parent::next();
}
public function rewind() {
$this->offset = 0;
parent::rewind();
}
public function seek($offset) {
if ($offset >= 0 && $offset < $this->count()) {
$this->offset = $offset;
}
parent::seek($offset);
}
public function offset() {
return $this->offset;
}
}
Example:
$array = array('value1','value2','value3');
$iter = new FooArrayIterator($array);
foreach ($iter as $v) {
echo ($iter->count() - $iter->offset() - 1).' more';
}
You can get the actual index:
foreach ($array as $index => $value) {
}
If you are working with an associative array there is no way to tell the current position of the internal array pointer. There is only an indirect way: you search for the current key in the keys of the array with:
foreach ($array as $index => $value) {
$position = array_search ($index, array_keys ($array));
echo ($position);
}
... but I guess count++ is a much more resource-friendly way.
You can:
$count = count($array);
foreach($array as $key => $value) {
$count--;
//$count elements are left
}
Yes, sort of.
foreach($array as $key=>$value)
// code
}
$key will be the array key, although if you want an actual integer count of iterations, and the keys are not numbered sequentially, or are strings, you will have to use a counter like in your original post.
Edit: to handle the last element without implementing a counter, you can use (if keys are int)
$foo = ($key == count($array)-1) ? "last element" : "any other element";
(janked from the manual comments - http://php.net/manual/en/control-structures.foreach.php)
Edit: if your keys are not integers, you can create a counter like you have in your code above, and substitute $key with your counter variable.
You're being a bit too picky :)
By the way the trick is to transform an associative array to an indexed array:
foreach ( array_values($array) as $key=>$value ){
echo $key; //yes, it will be an INT
echo ( count($array) - $key );
}
Without some pre-processing, such as your count() version, there isn't any way to know where you are in an associative array. At most you can check if you're at the end with end(), but there's no guarantee as to what order foreach() will retrieve the individual elements. Generally it's the same order they got added to the array, but not guarantees.
Another pre-processing option would be
$keys = array_keys($array);
$cnt = count($keys)
for ($i = 0; $i < $cnt; $i++) {
$element = $array[$keys[$i]];
}
and $i would tell you exactly how far through you've gone.