Removing JSON children by key in PHP - php

My goal is to have a function that can remove a specified json child, which could also be nested inside deeper.
My function looks like this:
private function removeJsonChild(String $jsonKey, String $jsonString)
{
$json = json_decode($jsonString, true);
$arr_index = array();
foreach ($json as $key => $value) {
if (is_array($value)) {
$json[$key] = $this->removeJsonChild($jsonKey, json_encode($value));
}
if ($key == $jsonKey) {
$arr_index[] = $key;
}
}
foreach ($arr_index as $i) {
unset($json[$i]);
}
return json_encode($json);
}
The function would work if i wouldn't check if a $value is an array and then call the function again recursively. But there is the problem i think. In the statement where i assign the return value of the function to $json[$key]. What am i doing wrong?
EDIT: definitely forgot a json_decode. New code looks like this:
private function removeJsonChild(String $jsonKey, String $jsonString)
{
$json = json_decode($jsonString, true);
$arr_index = array();
foreach ($json as $key => $value) {
if (is_array($value)) {
$json[$key] = json_decode($this->removeJsonChild($jsonKey, json_encode($value)));
}
if ($key == $jsonKey) {
$arr_index[] = $key;
}
}
foreach ($arr_index as $i) {
unset($json[$i]);
}
return json_encode($json);
}
EDIT2:
The function works now, however it slightly changes the json schema.
An JSON like this:
[
{
"id": 1,
"name": "oyzadsaigny647"
}
]
now becomes this:
{
"1": {
"id": 1,
"name": "oyzadsaigny647"
}
}

private function removeJsonChild(String $jsonKey, String $jsonString) {
$data = json_decode($jsonString, true);
$data = $this->removeKeyFromArray($key, $data);
return json_encode($data);
}
private function removeKeyFromArray(String $deleteKey, array $data) {
unset($data[$deleteKey]); // No need to check if it exists, it just does nothing in that case
foreach($data as $key => value) {
if(is_array($value)) {
$data[$key] = $this->removeKeyFromArray($deleteKey, $value);
}
}
return $data;
}
NOTE: this will work in case of dictionaries, i.e. array with actual keys. If you have a plain array such as [1, 10, 23, 15] the unset behaviour is wrong, as pointed out by #decezeā™¦

Related

return specific array form from function

i have this array
$array = [1, 2, 3, 4, 5];
and this function
function change($array) {
foreach ($array as $key => $value) {
$form[$key+5][$value-1] = $key-$value;
}
return $form;
}
change($array);
in it the form that i want to rearrange the array in is $form[$key+5][$value-1] = $key-$value; but i want to make it defined by a parameter like this
function change($array, $form) {
foreach ($array as $key => $value) {
$form;
}
return $form;
}
$x = change($array, $arr[$key+5][$value-1] = $key-$value);
$y = change($array, $arr[$key+5][$key+100] = $key+$value);
how can this be done?
Somebody will bash all of the evils of eval but if it is not user supplied (un-trusted) data, then this works:
function change($array, $form) {
foreach ($array as $key => $value) {
eval("\$result$form;");
}
return $result;
}
You need to call it with a string as shown:
$x = change($array, '[$key+5][$value-1] = $key-$value');
$y = change($array, '[$key+5][$key+100] = $key+$value');
This builds a string that looks like this: $result[$key+5][$key+100] = $key+$value; and evaluates it as PHP code.
It would be a lot more work, but you could pass in something to parse and adapt it to How to access and manipulate multi-dimensional array by key names / path?.

Parse JSON data from multiple options

I'm trying to parse JSON data in the format [{code:SE rate:1.294},{code:UK rate:2.353}] from this page:
http://www.mycurrency.net/service/rates
I have implemented an IP reader that detects the users location in a 2 letter country code. I want to pluck the correct data from that link with 'code' and return the value 'rate'. I was thinking I might have to do a foreach loop to iterate through all the countries?
This is my code, I hope this is what are you looking for.
First I create a new array $output to make it more easy to search
$string = file_get_contents("http://www.mycurrency.net/service/rates");
$json = json_decode($string, true);
foreach ($json as $key => $data) {
$output[$key]['code'] = $data['code'];
$output[$key]['rate'] = $data['rate'];
}
After that we use a function to search value in array and returning the key. I got it from here
function searchForRate($countryCode, $array) {
foreach ($array as $key => $val) {
if ($val['code'] === $countryCode) {
return $key;
}
}
return null;
}
and then I run the function with the first parameter as country code to get the keys of specific country code.
$find = searchForRate("BT", $output);
And then echo the rates from our $output array by key in $find variable
echo 'RATE = '.$output[$find]['rate'];
This is the complete codes
<?php
$string = file_get_contents("http://www.mycurrency.net/service/rates");
$json = json_decode($string, true);
foreach ($json as $key => $data) {
$output[$key]['code'] = $data['code'];
$output[$key]['rate'] = $data['rate'];
}
function searchForRate($countryCode, $array) {
foreach ($array as $key => $val) {
if ($val['code'] === $countryCode) {
return $key;
}
}
return null;
}
$find = searchForRate("BT", $output);
echo 'RATE = '.$output[$find]['rate'];
Example output:
RATE = 64.13

json decode array PHP

I'm trying to decode a json string, i want to get just langlinks value,
my json string is:
{
"batchcomplete": "",
"query": {
"pages": {
"105219": {
"pageid": 105219,
"ns": 0,
"title": "Cancer",
"langlinks": [
{
"lang": "ar",
"*": "\u0633\u0631\u0637\u0627\u0646"
}
]
}
}
}
}
I tried this code:
$results = json_decode($api_response, true);
$list = array();
foreach ($results['query']['pages'] as $k => $v)
{
var_dump($v);
foreach($v as $key => $val)
{
array_push($list, $val);
}
}
return $list;
But it does not accede to the value that I want, when i add
var_dump(array_key_exists('langlinks', $v));
it gives me false :/
I just tested this and this seems to return true
$source = file_get_contents('https://en.wikipedia.org/w/api.php?action=query&titles=Cancer&prop=langlinks&lllang=ar&format=json');
$results = json_decode($source, true);
foreach ($results['query']['pages'] as $k => $v)
{
var_dump(array_key_exists('langlinks', $v));die();
}
If you are still having trouble, maybe you can post more code?
$list = array();
$src = json_decode($api_response, true);
foreach ($src['query']['pages'] as $key => $langData) {
foreach ($langData['langlinks'] as $k => $ld);
// var_dump($ld['*']);
}
return $ld['*'];

PHP move duplicates in recursive array

I building a translation form that is build using a array filled with the translation keys, to keys are however often duplicated. As the form is builded in group i want to move the duplicates to the $translatables['global']
Note that what you're seeing in the image below is already placed in $translatables['modules']['Module_{{ModuleName}}']
As you can see in the image below, some fields are duplicates. those needs to be moved. The duplicates can be placed accross multiple elements.
I edit for the duplicate message: It ain't, its a question to move those values not to filter them (and keep 1 remaining), they need to be placed under a global section.
I solved it myself
class Tools_Array
{
public static function find_duplicates_recursive(&$array, $remove = false)
{
$duplicates = array();
$valueCounts = array_count_values(self::array_values_recursive($array));
foreach ($valueCounts as $key => $value) {
if ($value > 1)
{
$duplicates[] = $key;
}
}
if ($remove) {
foreach ($duplicates as $duplicate)
{
$array = self::remove_values_recursive($array, $duplicate);
}
}
return $duplicates;
}
public static function array_values_recursive($array)
{
$arr2 = array();
foreach ($array as $key => $value)
{
if(is_array($value))
{
$arr2 = array_merge(array_values_recursive($value), $arr2);
}else{
$arr2[] = $value;
}
}
return $arr2;
}
public static function remove_values_recursive($array, $needle)
{
foreach ($array as $key => $value)
{
if(is_array($value))
{
$array[$key] = self::remove_values_recursive($value, $needle);
}else{
if ($value == $needle)
{
unset($array[$key]);
}
}
}
return $array;
}
}
Then i can filter it with:
$duplicates = Tools_Array::find_duplicates_recursive($translatables, true);
$translatables['globaal'] = array_merge($translatables['globaal'], $duplicates);

Split an array into sub arrays

I would like to split an array:
$o = json_decode('[{"id":"1","color":"green"},{"id":"2","color":"green"},{"id":"3","color":"yellow"},{"id":"4","color":"green"}]');
based on the color attribute of each item, and fill corresponding sub arrays
$a = array("green", "yellow", "blue");
function isGreen($var){
return($var->color == "green");
}
$greens = array_filter($o, "isGreen");
$yellows = array_filter($o, "isYellow");
// and all possible categories in $a..
my $a has a length > 20, and could increase more, so I need a general way instead of writing functions by hand
There doesn't seem to exist a function array_split to generate all filtered arrays
or else I need a sort of lambda function maybe
You could do something like:
$o = json_decode('[{"id":"1","color":"green"},{"id":"2","color":"green"},{"id":"3","color":"yellow"},{"id":"4","color":"green"}]');
$greens = array_filter($o, function($item) {
if ($item->color == 'green') {
return true;
}
return false;
});
Or if you want to create something really generic you could do something like the following:
function filterArray($array, $type, $value)
{
$result = array();
foreach($array as $item) {
if ($item->{$type} == $value) {
$result[] = $item;
}
}
return $result;
}
$o = json_decode('[{"id":"1","color":"green"},{"id":"2","color":"green"},{"id":"3","color":"yellow"},{"id":"4","color":"green"}]');
$greens = filterArray($o, 'color', 'green');
$yellows = filterArray($o, 'color', 'yellow');
In my second example you could just pass the array and tell the function what to filter (e.g. color or some other future property) on based on what value.
Note that I have not done any error checking whether properties really exist
I would not go down the road of creating a ton of functions, manually or dynamically.
Here's my idea, and the design could be modified so filters are chainable:
<?php
class ItemsFilter
{
protected $items = array();
public function __construct($items) {
$this->items = $items;
}
public function byColor($color)
{
$items = array();
foreach ($this->items as $item) {
// I don't like this: I would prefer each item was an object and had getColor()
if (empty($item->color) || $item->color != $color)
continue;
$items[] = $item;
}
return $items;
}
}
$items = json_decode('[{"id":"1","color":"green"},{"id":"2","color":"green"},{"id":"3","color":"yellow"},{"id":"4","color":"green"}]');
$filter = new ItemsFilter($items);
$greens = $filter->byColor('green');
echo '<pre>';
print_r($greens);
echo '</pre>';
If you need more arguments you could use this function:
function splitArray($array, $params) {
$result = array();
foreach ($array as $item) {
$status = true;
foreach ($params as $key => $value) {
if ($item[$key] != $value) {
$status = false;
continue;
}
}
if ($status == true) {
$result[] = $item;
}
}
return $result;
}
$greensAndID1 = splitArray($o, array('color' => 'green', 'id' => 1));

Categories