public function onRun(int $currentTick){
foreach (glob($this->plugin->getDataFolder()."/players/*.json") as $plData) {
$str = file_get_contents($plData);
$json = json_decode($str, true);
$levels = $json["level"];
}
}
I want to get top 5 higher values from all json files in "players" folder, I only know how to get that value from all files, but don't know how to select 5 higher. Can someone help please?
EDIT: Json file looks like this:
{
"coins": 0,
"rank": "Guest",
"accept_friends": true,
"reward_time": 1440,
"level": "29",
"bio": "Today is very cool!c",
"progress": 24.939999999999998,
"local_ip": "10.0.0.1",
"registred": true,
"logged": true
}
Use usort!
Make a function that will handle your sorting:
function levelSort($a, $b)
{
return $a['level']>$b['level'];
}
next store your players to array, sort it and return first five elements:
public function onRun(int $currentTick){
$players = []; // declare aray with proper scope
foreach (glob($this->plugin->getDataFolder()."/players/*.json") as $plData) {
$str = file_get_contents($plData);
$json = json_decode($str, true);
$players[] = $json; // save to array
}
usort($players, 'levelSort'); // sort using custom function
return array_slice($players, 0, 5); // return 5 elements
}
Should work. didn't tested tho :D
Of course this example assuming that every $json is an array and $json['level'] exists and is int
You need to build an array of levels with $levels[] as you are overwriting $levels each time. Then just reverse sort and slice the top 5:
public function onRun(int $currentTick){
foreach (glob($this->plugin->getDataFolder()."/players/*.json") as $plData) {
$str = file_get_contents($plData);
$json = json_decode($str, true);
$levels[] = $json["level"];
}
rsort($levels);
return array_slice($levels, 0, 5);
}
If you want to return the entire top 5 arrays:
public function onRun(int $currentTick){
foreach (glob($this->plugin->getDataFolder()."/players/*.json") as $plData) {
$str = file_get_contents($plData);
$results[] = json_decode($str, true);
}
array_multisort(array_column($results, 'level'), SORT_DESC, $results);
return array_slice($results, 0, 5);
}
Why are you passing in an argument $currentTick and not using it? Maybe replace 5 with $currentTick so you can pass it in?
Related
Good night.
I'm trying to access all of the availableForExchange values on the return of a page below:
[
{
"code":"18707498",
"date":"2019-01-23T16:58:01",
"totalPriceInCents":14450,
"orderTotalPriceInCents":14450,
"status":"PGTO_NAO_CONFIRMADO",
"availableForExchange":false,
"paymentType":"CREDIT_CARD",
"installmentValueInCents":7225,
"installmentsNumber":2,
"paymentSummaries":[
{
"paymentType":"CREDIT_CARD",
"installmentsNumber":2,
"installmentValueInCents":7225,
"valueInCents":14450
}
],
"hasGiftCard":false
},
{
"code":"019741817156",
"date":"2017-06-11T19:09:06",
"totalPriceInCents":19110,
"orderTotalPriceInCents":19110,
"status":"ENTREGA_EFETUADA",
"availableForExchange":false,
"paymentType":"CREDIT_CARD",
"installmentValueInCents":9555,
"installmentsNumber":2,
"paymentSummaries":[
{
"paymentType":"CREDIT_CARD",
"installmentsNumber":2,
"installmentValueInCents":9555,
"valueInCents":19110
}
],
"hasGiftCard":false
}
]
I have already tried the following ways:
$data = curl_exec($ch);
$json = json_decode($data, true);
$str = $json['availableForExchange'];
print_r($str);
I need to access all values of: availableForExchange, search for true values and count (if true),
and save to a variable.
what you want to do is to filter the $json (it is an array)
$found = array_filter($json, function($entry) { return $entry['availableForExchange']; });
echo 'Entries: '.count($found);
print_r($found);
By using array_column to access the availableForExchange values directly, you can use array_filter with no callback (since the values in that column are boolean):
$json = json_decode($data, true);
$available = count(array_filter(array_column($json, 'availableForExchange')));
echo "$available available for exchange\n";
Output (for your sample data)
0 available for exchange
Demo on 3v4l.org
I am brand new to php.I have found questions that show how to remove key/value pairs from JSON files with php, but not array indexes.
I have worked out how to append values to arrays in a JSON file with json_decode(). But not how to remove values. I need to produce a function() that hunts for c and removes any value within an array in my JSON file. Below is a before and after of the expected outcome I need to produce with my php file.
// before
[["a", "c", "b"], ["c", "c"], [], ["c", "d"], ["d"], ["e"]]
// after
[["a", "b"], [], [], ["d"], ["d"], ["e"]]
Below is the function I have produced in order to add values to arrays in my JSON if this helps provide more context:
function appendClient($file, $post, $client) {
$a = fopen($file, "r");
$json = json_decode(fread($a, filesize($file)));
$json[$post][] = $client;
fclose($a);
$a = fopen($file, "w");
fwrite($a, json_encode($json));
fclose($a);
}
Use array_filter
function removeClient($file, $post, $client) {
$json = json_decode(file_get_contents($file));
$json[$post] = array_filter($json[$post], function($x) use($client) {
return $x != $client;
});
file_put_contents($file, json_encode($json));
}
This assumes all the elements of the array are either empty arrays or 1-element arrays containing the client name, as in the example you showed.
Take a look at array_filter and array_values functions.
[["a"],[],["b"],["c"]]
From the above input, I am assuming you are working with 2d array. Then, you can use the following function to do the job:
function removeValues($array, $value) {
$result = [];
foreach ($array as $row) {
$filtered = array_filter($row, function($entry) use($value) {
return $entry != $value;
});
// If you need to reset keys
$filtered = array_values($filtered);
$result[] = $filtered;
}
return $result;
}
Example:
$input = [["a"],[],["b"],["c"]];
$output = removeValues($input, "c");
print_r($output);
I'm having a graph like this:
Now, let's say I'm looking for a word CAT. I'm trying to make a nice code to walk this graph and find a word. I'd like it to find all existing positions of a word, not only first one.
The result for $graph->find('cat') should be:
return [
[1, 0, 6],
[1, 2, 3]
];
I have created such code in the past, but it was iterative. This time I'd like to try recursive.
Here's what I have so far:
I call it like this:
// LetterGraph is my own class
$graph = new LetterGraph($nodes);
$graph->find('cat');
And in my LetterGraph class I do the following:
public function find(string $word): array {
$result = [];
$firstLetter = mb_substr($word, 0, 1);
foreach ($this->letters as $node) {
if ($node->letter === $firstLetter) {
$result[] = $this->walk($word, [$node]);
}
}
return $result;
}
protected function walk(string $word, array $nodes): array {
$lastNode = end($nodes);
$letterToFind = mb_substr($word, count($nodes), 1);
foreach ($lastNode->neighbours as $neighbour) {
if ($neighbour->letter === $letterToFind) {
// is return okay here?
return $this->walk($word, array_merge($nodes, $neighbour);
}
}
}
Now, I'm not sure how to deal with recursive returns to make it give me the result I want.
It can be solved using Master theorem.
Assuming $node->id is the number you want to see in the resulting array, the recursion may look like
public function find(string $word, array $nodes = null): array
{
$firstLetter = mb_substr($word, 0, 1);
$rest = mb_substr($word, 1);
if (empty($nodes)) {
//top level call, start to search across all nodes
$nodes = $this->letters;
}
$result = [];
foreach ($nodes as $node) {
if ($node->letter === $firstLetter) {
if (empty($rest)) {
//exit recursion
$result[] = [$node->id];
} else {
//recursively search rest of the string
$branches = $this->find($rest, $node->neighbours);
if (!empty($branches)) {
foreach ($branches as $branch) {
$result[] = array_merge([$node->id], $branch);
}
}
}
}
}
return $result;
}
I am trying to parse some data and just cant seem to figure it out myself.
I have tried using recursion and got the general idea but i cant seem to work out getting the array indexes to line up right. Here is what I have so far:
public function reverse() {
$reversedValues= array();
foreach ( $this->sorted as $key=>$value ) {
array_push( $this->reversedPaths ,$key );
array_push( $reversedValues , $value );
//print_r($this->reversed);
echo "<br />";
}
$this->reversed = $this->stringToArray($this->reversedPaths[0] , $reversedValues);
var_dump($this->reversed);
return json_encode($this->reversed , false);
}
private function stringToArray($path , $values , $count = 0) {
$separator = '/';
$pos = strpos($path, $separator);
if ($pos === false) {
//check for numbers so we know to add those to an json object
if (is_numeric($path)) {
//add it to the parent array of values...
}
$reversed = array(
$path => $values[$count],
);
return $reversed;
}
$key = substr($path, 0, $pos);
$path = substr($path, $pos + 1);
$reversed[$key] = $this->stringToArray($path , $values , $count);
$count++;
//read in next path string
if (array_key_exists( $count ,$this->reversedPaths)) {
$currentpos = strpos($this->reversedPaths[$count], $path.$separator);
$currentPath = substr($this->reversedPaths[$count], $currentpos );
$nextpos = strpos($currentPath, $separator);
if ($nextpos === false) {
} else {
$nextPath = substr($currentPath, $nextpos + 1);
$nextKey = substr($nextPath, 0, $nextpos);
echo $nextKey;
echo $nextPath;
// echo $nextKey;
//if this key equals first value of next path dont return but process recurssion again on it
if ($nextKey !== false ) {
$reversed[$key][$nextKey] = $this->stringToArray($nextPath , $values , $count);
}
}
} else {
}
return $reversed;
}
I was trying to read in the next path data to check if it is within the same array index but i just couldn't get it working. I know i am over complicating it but it doesn't seem like there is any easy way to accomplish this...
I had a crack at this. Based on the details you provided, it looks like you are trying to create a tree, like a directory structure: each / delimited string in the key represents a 'depth'. The solution I found was to create a multidimensional array for each element, parsing the current key into levels and recursively merge/replace the result into a master 'tree' array. This is what I have:
// original JSON string
$json = '{
"one/two": 3,
"one/four/0": 5,
"one/four/1": 6,
"one/four/2": 7,
"eight/nine/ten": 11
}';
// convert to a PHP multidimensional array
$array = json_decode($json, true);
// init an array to hold the final result
$tree = [];
// iterate over the array of values
// explode the key into an array 'path' tokens
// pop each off and build a multidimensional array
// finally 'merge' the result into the result array
foreach ($array as $path => $value) {
$tokens = explode('/', $path);
while (null !== ($key = array_pop($tokens))) {
$current = [$key => $value];
$value = $current;
}
$tree = array_replace_recursive($tree, $value);
}
// show the result!
print_r(json_encode($tree, JSON_PRETTY_PRINT));
Yields:
{
'one': {
'two': 3,
'four': [5, 6, 7]
},
'eight': {
'nine': {
'ten':11
}
}
}
Hope this helps :)
I am checking that certain elements in sub-arrays in a multidimensional array are not equal to a value and un-setting the array with that value from the multi array. I built a function so that I could easily implement this, however it doesn't appear to be working.
function multi_unset($array, $unset) {
foreach($array as $key=>$value) {
$arrayU = $array[$key];
$check = array();
for($i = 0; $i < count($unset); $i++) { // produces $array[$key][0, 2, 3]
array_push($check, $arrayU[$unset[$i]]);
}
if(in_array("-", $check)) {
unset($array[$key]);
}
}
return $array;
}
$arr = array(array("-", "test", "test", "test"), array("test", "test", "test", "test"));
$unset = array(0, 2, 3); // keys in individual arrays to check
multi_unset($arr, $unset);
print_r($arr); // Should output without $arr[0]
In this case, I'm checking if each sub-array has a "-" value in it and un-setting the array from the multi array. I am only checking specific keys in the sub-arrays (0, 2, 3) however it outputs an array without any changes. I figured I must have some scoping wrong and tried to use "global" everywhere possible, but that didn't seem to fix it.
Modified your version a bit and handled the return value.
function multi_unset($array, $unset)
{
$retVal = array();
foreach($array as $key => $value)
{
$remove = false;
foreach($unset as $checkKey)
{
if ($value[$checkKey] == "-")
$remove = true;
}
if (!$remove)
$retVal[] = $value;
}
return $retVal;
}
$arr = array(array("-", "test", "test", "test"), array("test", "test", "test", "test"));
$unset = array(0, 2, 3);
$arr = multi_unset($arr, $unset);
print_r($arr);
You may want to do some reading into Passing by Reference vs passing by value in PHP.
Heres some code that works with the given data set....
// Note the pass by reference.
function multi_unset(&$array, $unset) {
foreach($array as $pos => $subArray) {
foreach($unset as $index) {
$found = ("-" == $subArray[$index]);
if($found){
unset($subArray[$index]);
// Ver 2: remove sub array from main array; comment out previous line, and uncomment next line.
// unset($array[$pos]);
}
$array[$pos] = $subArray; // Ver 2: Comment this line out
}
}
//return $array; // No need to return since the array will be changed since we accepted a reference to it.
}
$arr = array(array("-", "test", "test", "test"), array("test", "test", "test", "test"));
$unset = array(0, 2, 3);
multi_unset($arr, $unset);
print_r($arr);