Sorting a table similar to JSON - php

I would like to know how to sort my array alphabetically which is like
[
{"people":"Julien SMITH","uid":"598"},
{"people":"John SMITH","uid":"7232"}
]
I tried with
array_multisort($myArray['people'],SORT_ASC,$myArray['uid'])
But of course it doesn't work because people and uid are not really columns of the table...
I can't find something similar to my case..
Thanks for your help

Use usort() function. It will do exactly what you want.
$jsonObj = '[
{"people":"Julien SMITH","uid":"598"},
{"people":"Don SMITH","uid":"7232"},
{"people":"Allan SMITH","uid":"3232"}
]';
$arrObj = json_decode($jsonObj,true);
function build_sorter($key) {
return function ($a, $b) use ($key) {
return strnatcmp($a[$key], $b[$key]);
};
}
usort($arrObj, build_sorter('people'));
foreach ($arrObj as $item) {
echo $item['people'] . ', ' . $item['uid'] . "n";
}

First you need to convert your json object to array. Then you can apply sorting
$json_obj = '[
{"people":"Julien SMITH","uid":"598"},
{"people":"John SMITH","uid":"7232"}
]';
$myArray = json_decode($json_obj,true);
array_multisort($myArray,SORT_ASC);
echo json_encode($myArray); // op: [{"people":"John SMITH","uid":"7232"},{"people":"Julien SMITH","uid":"598"}]

Related

Remove JSON array index that holds specific value with PHP

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);

Reform PHP associated array

I have an associative array:
$input = [
['key'=>'x', 'value'=>'a'],
['key'=>'x', 'value'=>'b'],
['key'=>'x', 'value'=>'c'],
['key'=>'y', 'value'=>'d'],
['key'=>'y', 'value'=>'e'],
['key'=>'z', 'value'=>'f'],
['key'=>'m', 'value'=>'n'],
];
And I want to reform it simple in:
$output = [
'x'=>['a','b','c'],
'y'=>['d','e'],
'z'=>'f',
'm'=>'n'
]
So basically, conditions are:
1. If same key found then put values in an array.
2. If no same key found then value remains string.
You can replace associative array with object if you are more comfortable with objects.
Here is my working solution for this problem:
foreach($input as $in){
if(!empty($output[$in['key']])){
if(is_array($output[$in['key']])){
$output[$in['key']][] = $in['value'];
continue;
}
$output[$in['key']] = [$output[$in['key']],$in['value']];
continue;
}
$output[$in['key']] = $in['value'];
}
print_r($output);
However I believe that it can be done in much compact and efficient way.
Please comment your answers if someone has better solution.
Your help is much appreciated!
Reformat array to [ [ x=>a ], [x=>b],.. ] and merge all sub-arrays
$input = array_map(function($x) { return [$x['key'] => $x['value']]; }, $input);
$input = array_merge_recursive(...$input);
print_r($input);
demo
I would suggest
<?php
$input = [
['key'=>'x', 'value'=>'a'],
['key'=>'x', 'value'=>'b'],
['key'=>'x', 'value'=>'c'],
['key'=>'y', 'value'=>'d'],
['key'=>'y', 'value'=>'e'],
['key'=>'z', 'value'=>'f'],
['key'=>'m', 'value'=>'n'],
];
$reducer = function($carry, $item) {
$carry[$item['key']][] = $item['value'];
return $carry;
};
$mapper = function ($item) {
if (count($item) === 1) {
return $item[0];
}
return $item;
};
$output = array_map($mapper, array_reduce($input, $reducer, []));
var_dump($output);
You can see the result here: https://3v4l.org/8JjjS
You can use array_reduce to loop over an existing array and build up a new one:
$output = array_reduce($input, function ($carry, $i) {
$carry[$i['key']][] = $i['value'];
return $carry;
}, []);
Each element in $input is passed to the anonymous function, along with the $carry variable that's being built up as we go along. Inside, we just add each value to a sub-element indexed by key. The third argument [] is to set the initial value of the result to an empty array.
See https://eval.in/935015
(I'm assuming that the duplicate x keys in the question are a typo, and that the second is supposed to z, since that matches up with your suggested output)
For your original code you may find extract() interesting. I replaced the continue-s with else-s, but that is more like a matter of taste:
foreach($input as $in){
extract($in);
if(!empty($output[$key])){
if(is_array($output[$key])){
$output[$key][] = $value;
} else {
$output[$key] = [$output[$key],$value];
}
} else {
$output[$key] = $value;
}
On a side note I would probably use two much simpler loops, one for building lists and another for extracting single elements:
foreach($input as $in){
$output[$in['key']][] = $in['value'];
/* or: extract($in);
$output[$key][]=$value; */
}
foreach($output as $key => $value){
if(count($value)==1){
$output[$key]=$value[0];
}
}

PHP - What is the best way to access a property of an object which is an array element

I have an object which is an array of JSON objects. Kinda Like this,
$object = [
{
"id":1,
"name":"blue",
"order":4
},
{
"id":2,
"name":"green",
"order":6
},
{
"id":3,
"name":"yellow",
"order":2
}
]
I wanted to access the properties in a simple way and a single line maybe like this,
Say if I wanted the "order" of the object with name "blue"
$blue_order = $object[something]->[name="blue"]->order;
Kinda mixed Jquery in this. But I hope you understand. Right now the best I've got is this,
for($i=0; $i<count($object); $i++){
if($object[$i]->name == "blue"){
$blue_order = $object[$i]->order;
}
}
This seems very inefficient though and I don't want to use a loop because the array is very large and looping through it will be very slow. So how do I do this?
I used a "for" loop instead of foreach because the array can be null. And also the order of the array elements will not always be the same.
So I can't do something like
$object[0]->order
<?php
$arr = array(
array('id'=>1,'name'=>'blue','order'=>4),
array('id'=>2,'name'=>'green','order'=>6),
array('id'=>3,'name'=>'yellow','order'=>2),
);
// $json is JSON version of the arrays in $arr
$json = json_encode($arr);
// show $json
echo $json . "\n";
// create arrays from JSON so it can be used in PHP easier
$obj = json_decode($json);
$color = 'blue';
$blue_order = array_filter($obj, function($i) use ($color) { return $i->name == $color; })[0]->order;
echo "Blue Order: " . $blue_order;
You may be able to use array_filter to help this become a one-liner. I included the json_decode and json_encode so I could have a complete example.
You could still use foreach but check if the array isn't empty first, like this:
if(!empty($object)){
foreach($object as $element){
if($element->name == "blue"){
$blue_order = $element->order;
}
}
}
Also, your code looks efficient to me, what I would probably add is a break after you find the value, like this:
if(!empty($object)){
foreach($object as $element){
if($element->name == "blue"){
$blue_order = $element->order;
break;
}
}
}
If your object has a lot of information and you're going to do a lot of searches, then you could do some pre-processing so it get easier to search, like this:
$object_by_name = array();
if(!empty($object)){
foreach($object as $element){
$object_by_name[$element->name] = $element;
}
}
Then, you could search it like this:
if(!empty($object_by_name['blue'])){
$blue_order = $object_by_name['blue']->order
}
Keep it simple.
You're writing way too much code.
$array_list = ($array_list)?:[];
$array_list = array_filter($array_list,function($var) {
return ($var->name=="blue");
});
$order = ($array_list)? $array_list[0]->order :'';

array_walk_recursive doesn't seem to work

I want to apply a function to each element/prop of an object but it seems array_walk_recursive() does not work on object. i.e:
if( $re = $con->query("SELECT id, created_date, contents FROM " .
POST_DATA . " WHERE type = 'news' ORDER BY ".
"created_date DESC LIMIT $amount") ) {
if( $re->num_rows != 0 ) {
while( $ob = $re->fetch_object() ) {
$ob = array_walk_recursive( $ob, "_output" );
print_r($ob);
die();
}
}
}
would simply return '1'.
How might I resolve this?
It's actually returning a value of True for array_walk_recursive. If you look at the function's documentation, you'll see that what this method is doing is calling the function _output for each item and key in the object.
You should also have some code that looks similar to this, I would imagine, to get it to work correctly:
function _output($data, $key) {
echo "For the key $key, I got the data: ";
print_r($data);
}
Where _output is called because that is the stringified name that you gave in the array_walk_recursive function. That should print your values to the screen.
Edit:
It seems that I'm not actually answering what you were originally wanting to do, though. If you're wanting to apply a function to every element of an array, I would suggest that you look at array_map. You can use array_map like this:
function double($item) {
return 2 * $item;
}
array_map('double', $item);
Ultimately, if the recursion is something that you desire, you could probably do something like this:
function callback($key, $value) {
// do some stuff
}
function array_map_recursive($callback, $array) {
$new_array = array()
foreach($array as $key => $value) {
if (is_array($value)) {
$new_array[$key] = array_map_recursive($callback, $value);
} else {
$new_array[$key] = call_user_func($callback, $key, $value);
}
}
return $new_array;
}
array_map_recursive('callback', $obj);
That would return another array like $obj, but with whatever the callback was supposed to do.

PHP: Create array of arrays, ignoring empty arrays

I need to create an array of arrays.
I have been using array_map(null,$a,$b,$c) to do this and it works fine, however, it doesn't work if one of the mapped arrays doesn't exist.
To get around this problem I have used:
$myArray= array();
if (isset($a)) {
array_push($myArray,$a);
}
if (isset($b)) {
array_push($myArray,$b);
}
if (isset($c)) {
array_push($myArray,$c);
}
Is there a more elegant/shorter method of writing this?
I've tried applying some functions via array_map($function,$a,$b,$c) but with no luck.
$myArray = array_filter(array($a, $b, $c));
You could use the following function:
function joinArrays(){
$arrays = func_get_args();
$output = array();
foreach($arrays as $array){
if(!empty($array)) array_push($output, $array);
}
return $output;
}
call like: joinArrays($a, $b, $c, etc..);

Categories