A folder on my server holds a variable number of images. I'm working on a PHP script that is intended to retrieve the entire list of files there (a list of filenames) and create an associative array like so:
$list = array(1=>"image1.png", 2=>"image2.png", ...);
Basically, the list vector starts as empty and when a new image is found, its name has to be added to the list, with an incremented index: i=>"image[i].png"
How do I go about achieving this? Or in other words, how do I push a new element to my array?
I'm not sure why you are referring to this as an associative-array, but if you want to add somethign to an array, do it like this
$list = array();
$list[] = "image1.png";
$list[] = ....;
$list[] = "imagei.png";
If you want to push new item to your array, try with:
$list[] = "image" + ( count($list) + 1 ) + ".png";
If your items' indexes starts with 1, add +1 in the name as described above. If you are starting from 0 as it is natural behaviour, skip it and use as described below:
$list[] = "image" + count($list) + ".png";
So you are in fact re-implementing glob()?
$list = glob('/path/to/images/*.png');
If you are really want to reimplement it yourself
$i = 0;
$list = array();
while (file_exists('/path/to/image' . (++$i) . '.png'))
$list[$i] = "image$i.png";
Related
In an Array with normal numerical keys ( $file_array_for_editing ), I want to move a set of consecutive X number of values below the next set of X values.
Example: If a group of X values is 10, then in an Array of 50, I have 5 sets of 10 values. I want to move the 10 values in set 3 - below the 10 values in set 4.
So that : Set1(10 values) , Set2(10 values) , Set3(10 values) , Set4(10 values) , Set5(10 values)
Becomes: Set1(10 values) , Set2(10 values) , Set4(10 values) , Set3(10 values) Set5(10 values)
Since I don't know a better way, this is how I have done it now - by what I believe is switching the values:
$file_array_for_editing = [];
for($i=1; $i <= 50; $i++) {
$file_array_for_editing[] = $i;
}
$number_in_one_set = 10 ;
$set_number_to_move = 3 ;
$f = $file_array_for_editing ;
$s = ($set_number_to_move - 1) * $number_in_one_set ; // (3 - 1) * 10 = 20
list(
$f[$s+0],$f[$s+1],$f[$s+2],$f[$s+3],$f[$s+4],$f[$s+5],$f[$s+6],$f[$s+7],$f[$s+8],$f[$s+9],$f[$s+10],$f[$s+11],$f[$s+12],$f[$s+13],$f[$s+14],$f[$s+15],$f[$s+16],$f[$s+17],$f[$s+18],$f[$s+19]
) =
[$f[$s+10],$f[$s+11],$f[$s+12],$f[$s+13],$f[$s+14],$f[$s+15],$f[$s+16],$f[$s+17],$f[$s+18],$f[$s+19],$f[$s+0],$f[$s+1],$f[$s+2],$f[$s+3],$f[$s+4],$f[$s+5],$f[$s+6],$f[$s+7],$f[$s+8],$f[$s+9]];
$file_array_for_editing = $f ;
At the end, the numerical keys stay properly in order, from 0 to 49.
I need help finding a way to do this where I can vary the $number_in_one_set
If possible, I would appreciate help finding a solution where it is clearly apparent what is being done, so that after a year, when I look at the code again, it will be easy to understand. (as in, even now, I just vaguely understand why the list() above works)
Possibly following might help you on your way. You can change the 'sets' you'd like to switch using array $switch.
<?php
$arr = [];
for($i=1; $i <= 50; $i++) {
$arr[] = $i;
}
$set = 10; // each set has 10 items
$switch = [3, 4]; // switch element 3 vs. 4
$newArr = array_chunk($arr, $set); // chop array in chunks of size $set
// swap
$tmp = $newArr[$switch[0]]; // $temp=$newArr[3]
$newArr[$switch[0]] = $newArr[$switch[1]]; // $newArr[3]=newArr[4]
$newArr[$switch[1]] = $tmp; // $newArr[4]=$newArr[3]
$result = [];
array_walk_recursive($newArr, function($el) use (&$result) { $result[] = $el; }); // flatten array
EDIT
array_walk_recursive() applies the callback function (function($el)) to each element of nested array $newArr.
Each element of array $newArr, referenced by $el will be pushed into array $result, a flat indexed array.
Also, because the anonymous function (closure) writes to flat array $result which is defined in the parent scope, we need to employ the use language construct.
source manual: Closures may also inherit variables from the parent scope. Any such variables must be passed to the use language construct.
working demo
#jibsteroos - I really like the method you provided (which #CBroe also suggested) - reason being that it allows any two sets anywhere within the original array to be swapped.
After some thought, I find I prefer using the method below, even though it is a little long winded - reason being my use case is only to exchange a set with the one below it.
<?php
$arr = []; // Setting up a sample array
for($i=1; $i <= 50; $i++) {
$arr[] = $i;
}
$set_size = 10 ; // 10 items per set
$set = 3 ; // set to move down
$set_to_move = ($set - 1) * $set_size; // start position of this set in the array - 20
print_r($arr) ;
echo '<hr>';
$slice1 = array_slice($arr,0,$set_to_move);
print_r($slice1) ; // from the start of the array - to the start of the set to move
echo '<hr>';
$slice2 = array_slice($arr,$set_to_move,$set_size);
print_r($slice2) ; // the set to move
echo '<hr>';
$slice3 = array_slice($arr,$set_to_move + $set_size,$set_size);
print_r($slice3) ; // the set after the set to move
echo '<hr>';
$slice4 = array_slice($arr,$set_to_move + (2 * $set_size));
print_r($slice4) ; // the rest of the array
echo '<hr>';
$arr_edited = array_merge($slice1,$slice3,$slice2,$slice4,);
print_r($arr_edited) ; // All 4 arrays combined in the new order
echo '<hr>';
I am trying to merge two JSON , but instead of overwriting the value if it is found, I want to ADD the value if it is found For exemple, assuming I have tje following three values.
$a = "[{"base":"10","touch":true,"flatfooted":true}]"
$b = "[{"natural armor":"2","touch":false,"flatfooted":true}]"
$c = "[{"natural armor":"3","touch":false,"flatfooted":true}]"
I would like to get the following result:
"[{"base":"10","touch":true,"flatfooted":true},{"natural armor":"5","touch":false,"flatfooted":true}]"
But I'm getting lost in the way.
Thank you for the help.
Also, asking in advance to avoid asking in another question: How can I turn every JSON object into a different array?
Assuming the result JSON, something like
$final[0]['base'] = 10,
$final[0]['touch'] = true,
$final[0]['flatfooted'] = true,
$final[1]['natural armor'] = 5,
$final[1]['touch'] = false,
$final[1]['flatfooted'] = true
Here's a start, I can't finish it because I have to leave. Good luck!
<?php
$a = '[{"base":"10","touch":true,"flatfooted":true}]';
$b = '[{"natural armor":"2","touch":false,"flatfooted":true}]';
$c = '[{"natural armor":"3","touch":false,"flatfooted":true}]';
//Decode values to arrays and get first item.
$a = json_decode($a, true)[0];
$b = json_decode($b, true)[0];
$c = json_decode($c, true)[0];
//Put them all in a array
$abc = [$a, $b, $c];
//Compare keys of all arrays, and put the ones with no diffs in a array
$noDiff = [];
foreach ($abc as $idx => $character) {
//Skip first because we use it in the foreach
for ($i = 1; $i < count($abc); $i++) {
$diff = array_diff_key($character, $abc[$i]);
if (empty($diff)) {
$noDiff[] = $character;
$noDiff[] = $abc[$i];
}
}
//Remove item from $abc and reset index keys
array_splice($abc, $idx, 1);
}
//$noDiff will now contain array $b and $c and we know they both have the same keys.
//We need to be sure natural armor contains numeric values and that touch and flatfooted
//have both the same boolean value.
$merged = [];
$canCombine = true;
foreach ($noDiff[0] as $key => $value) {
if (!is_numeric($value) || is_numeric($noDiff[1][$key]) {
$canCombine = false;
} else {
}
}
echo "<pre>";
var_dump(
$noDiff
);
echo "</pre>";
You can turn any JSON string into an array using:
$result = json_decode($jsonString,true) ;
If you want each JSON string to end up as a separate element of an array you can use:
$final[] = json_decode($jsonString,true) ;
So, in your case you could use:
$final[] = json_decode($a,true) ;
$final[] = json_decode($b,true) ;
$final[] = json_decode($c,true) ;
Though I would recommend a loop in case you don't always have three (e.g., $a, $b & $c).
You should always check json_last_error() after each json_decode() to make sure you didn't generate an error.
Since JSON is serialized data, you need to parse the two json objects you need to merge, then add the result of any fields, then you can update the values of one of your original json objects and serialize the data.
I haven't used PHP before, but here is an article I found on parsing json objects in PHP. http://php.net/manual/en/function.json-decode.php
Hope that helps.
1) Same AC bonuses DO NOT stack. That means you can't add two natural armors for one unit. You can however do (base + dexterity + natural + size + armor + shield)
2) Why are "touch" and "flat footed" booleans? You just add different subsets of AC
touch = base + dexterity + natural + size
flat footed = base + armor + shield
3) In case you are indeed talking about DnD, I hope you want to make a tool for yourself and your friends to use, cause you can't just publish a tool for DnD, it's copyrighted.
I have the following simple array and php
$my_array=array("a"=>"red","b"=>"green","c"=>"blue","d"=>"purple","e"=>"yellow");
$match_key = array_search("blue",$my_array);
echo $match_key;
I would like to create two variables that are the array item either side of $match_key. So in the example above I am trying to end up with...
$previous = 'green';
$next = 'purple';
What is the best way to tackle this?
If you have no way of changing your array structure, you could do the following by "creating" a new array with just the values of the original array, via array_values()
$vals = array_values($my_array);
$match_key = array_search("blue", $vals);
echo "PREV: ". $vals [($match_key - 1)] . "\n";
echo "CURR: ". $vals[$match_key] ."\n";
echo "NEXT: ". $vals [($match_key + 1)] . "\n";
Which returns:
PREV: green
CURR: blue
NEXT: purple
Now you'll need to do key handling/etc to ensure the code doesn't throw any errors and handles your keys in a subtle way.
There are various other ways (inspired by this post) that harnesses in-built functions, although seemingly taking longer to process:
$match_key = array_search("blue", $my_array);
// loop through and set the array pointer to the $match_key element
while (key($my_array) !== $match_key) next($my_array);
$current = $my_array[$match_key];
$prev = prev($my_array);
next($my_array); // set the array pointer to the next elem (as we went back 1 via prev())
$next = next($my_array);
Which returns the previous, current & next as below:
CURRENT: blue
PREVIOUS: green
NEXT: purple
Using array_values() is the way to go. This creates a new indexed array in the same order as your original array.
Then you can search that for your value using array_search() which returns the numeric index. Then just +1 for the next and -1 for the previous.
Of course you may want to verify that the value you are searching for actually exists. If so, then ensure index+1 and index-1 also exist and set as null if they don't.
Something like this:
$my_val = 'blue';
$int_indexes = array_values($my_array); // store all values into integer indexed array
if ($index = array_search($my_val, $int_indexes)) { // don't set prev-next if value not found
$prev = array_key_exists($index - 1, $int_indexes) ? $int_indexes[$index - 1] : null;
$next = array_key_exists($index + 1, $int_indexes) ? $int_indexes[$index + 1] : null;
}
echo "previous: $prev" . '<br>';
echo "this: $my_val" . '<br>';
echo "next: $next";
Gives you results:
// previous: green
// this: blue
// next: purple
And if your searched value is at the beginning or end, no worries, you just get a null value. And it your searched value isn't found, no worries, you just get 2 null values.
What is the best way to check if an multi-dimension array contains 2 or more equal value and only return the first one .
ex : i have an array of people that contain
[0][firstName] = 'John';
[0][lastName] = 'Doe';
[N][firstName] = 'Marco';
[N][lastName] = 'Polo';
[120][firstName] = 'John';
[120][lastName] = 'Doe';
Should detect that the index 120 is a duplicate and remove it .
I'm looking for the best performance , i don't want to loop on the array and check every time if i have the value or not .
Is there something faster ?
It is the element distinctness problem which is basically O(NlogN) via sorting and iterating (after sorting, duplicates will be adjacent to each other - so easy to detect them)
However, it can be done also in O(N) on average and with O(N) additional space by storing all elements to a hash table while iterating, and breaking if an element already exists.
You might also want to store the original index of each element if you will later need it (and don't use the index as key).
pseudo code:
map <- empty hash map
for each element e with idx i in list (in ascending order of i):
if (map.contains(e)):
e is a dupe, the first element is in index map.get(e)
else:
map.add(e,i)
You can try
// Generate Possible name with duplicate
$names = array("John","Doe","Polo","Marco","Smith");
$array = array();
for($i = 0; $i < 20; $i ++) {
$key = mt_rand(0, 1000);
$array[$key]["firstName"] = $names[array_rand($names)];
$array[$key]["lastName"] = $names[array_rand($names)];
}
// Start Sorting process
ksort($array);
// Start Storage
$data = $hash = array();
// Loop and porpulate new array
foreach ( $array as $k => $v ) {
$h = sha1($v['firstName'] . $v["lastName"]);
isset($hash[$h]) or $data[$k] = $v and $hash[$h] = 1;
}
var_dump($data);
$arr[] = $new_item;
Is it possible to get the newly pushed item programmatically?
Note that it's not necessary count($arr)-1:
$arr[1]=2;
$arr[] = $new_item;
In the above case,it's 2
end() do the job , to return the value ,
if its help to you ,
you can use key() after to petch the key.
after i wrote the answer , i see function in this link :
http://www.php.net/manual/en/function.end.php
function endKey($array){
end($array);
return key($array);
}
max(array_keys($array)) should do the trick
The safest way of doing it is:
$newKey = array_push($array, $newItem) - 1;
You can try:
max(array_keys($array,$new_item))
array_keys($array,$new_item) will return all the keys associated with value $new_item, as an array.
Of all these keys we are interested in the one that got added last and will have the max value.
You could use a variable to keep track of the number of items in an array:
$i = 0;
$foo = array();
$foo[++$i] = "hello";
$foo[++$i] = "world";
echo "Elements in array: $i" . PHP_EOL;
echo var_dump($foo);
if it's newly created, you should probably keep a reference to the element. :)
You could use array_reverse, like this:
$arr[] = $new_item;
...
$temp = array_reverse($arr);
$new_item = $temp[0];
Or you could do this:
$arr[] = $new_item;
...
$new_item = array_pop($arr);
$arr[] = $new_item;
If you are using the array as a stack, which it seems like you are, you should avoid mixing in associative keys. This includes setting $arr[$n] where $n > count($arr). Stick to using array_* functions for manipulation, and if you must use indexes only do so if 0 < $n < count($arr). That way, indexes should stay ordered and sequential, and then you can rely on $arr[count($arr)-1] to be correct (if it's not, you have a logic error).