Straight to classify the JSON data - php

There is a sorted list of questions without classification and I want to sort this list of questions. Because the system of the school works like this. I tried to do this, but I could only do this because I had little PHP knowledge.
In the JSON file, the first part is the question, followed by 4 options and the question begins again.
The amount of questions does not change. Always 4.
Currently JSON file:
$jsonData = '["questionText1","option1","option2","option3","option4","questionText2","option1","option2","option3","option4","questionText3","..."]'; // x150 text
My code:
$jsonParse = json_decode($jsonData, true);
foreach ($jsonParse as $json) {
$cikis[] = array('q' => $json[0]);
}
var_dump($cikis);
Goal:
$jsonData = [
{'q':'questionText','o1':'option1','o2':'option2','o3':'option3','o4':'option4'},
{'q':'questionText','o1':'option1','o2':'option2','o3':'option3','o4':'option4'}
]
I looked for a question like this but couldn't find it. What do I have to do to classify the question and question options separately? like the example above.

You can simply use array_chunk to split your source data into chunks of five items, since each grouping always consists of 1 question + 4 options.
$chunks = array_chunk($jsonParse, 5);
This will give you an array of five-item chunks, with each chunk containing the question as the first item [0], and the options as items [1]...[4]. If you want to turn them into associated arrays, you can do that for example using array_map and array_combine:
$namedChunks = array_map(function($chunk) {
return array_combine(['q', 'o1', 'o2', 'o3', 'o4'], $chunk);
}, $chunks);
This will give you an array with named keys, which you can json_encode($namedChunks) for the output you're looking for. (Your example isn't valid JSON, though!)
A foreach loop and a "manual" building of the associated arrays will also work, and probably will be marginally faster. I'm in the habit of using straight-up loops in code where performance adds up (either frequently called, or with massive data), and using the more elegant array_* functions in favor of more explicit and readable code, where raw performance is less consequential.

You can use array_chunk() to split an array into samesized chunks:
<?php
$numberOfElementsPerChunk = 5; // 1 question + 4 options
$jsonData = '["questionText1","option1","option2","option3","option4","questionText2","option1-2","option2-2","option3-2","option4-2","questionText3","option1-3","option2-3","option3-3","option4-3","questionText4","option1-4","option2-4","option3-4","option4-4"]';
$jsonParse = json_decode($jsonData, true);
$chunks = array_chunk($jsonParse, $numberOfElementsPerChunk);
$result = [];
foreach ($chunks as $question) {
$set = [
'q' => $question[0],
'o1' => $question[1],
'o2' => $question[2],
'o3' => $question[3],
'o4' => $question[4],
];
$result[] = $set;
}
print_r(json_encode($result));
Output:
[{"q":"questionText1","o1":"option1","o2":"option2","o3":"option3","o4":"option4"},{"q":"questionText2","o1":"option1-2","o2":"option2-2","o3":"option3-2","o4":"option4-2"},{"q":"questionText3","o1":"option1-3","o2":"option2-3","o3":"option3-3","o4":"option4-3"},{"q":"questionText4","o1":"option1-4","o2":"option2-4","o3":"option3-4","o4":"option4-4"}]

Related

PHP extract key-value in array json and restructure

Any idea on how to restructure the json below:
$jsonArray = [{"Level":"77.2023%","Product":"Milk","Temperature":"4"},
{"Level":"399.2023%","Product":"Coffee","Temperature":"34"},
{"Level":"109.2023%","Product":"Chocolate","Temperature":"14"}]
Expected outcome:
$expected = {"Milk":{"Level":"77.2023%","Temperature":"4"},
"Coffee":{"Level":"399.2023%","Temperature":"34"},
"Chocolate":{"Level":"109.2023%","Temperature":"14"}
}
I'm new and my thinking is get the product value in array and again use foreach loop to find the others value? .
Here's one possibility:
$jsonArray = '[{"Level":"77.2023%","Product":"Milk","Temperature":"4"},
{"Level":"399.2023%","Product":"Coffee","Temperature":"34"},
{"Level":"109.2023%","Product":"Chocolate","Temperature":"14"}]';
$output = array();
foreach (json_decode($jsonArray, true) as $row) {
$product = $row['Product'];
$output[$product] = $row;
unset($output[$product]['Product']);
}
echo json_encode($output);
Output:
{"Milk":{"Level":"77.2023%","Temperature":"4"},
"Coffee":{"Level":"399.2023%","Temperature":"34"},
"Chocolate":{"Level":"109.2023%","Temperature":"14"}
}
Demo on 3v4l.org
This made some trick
$a = '[{"Level":"77.2023%","Product":"Milk","Temperature":"4"},
{"Level":"399.2023%","Product":"Coffee","Temperature":"34"},
{"Level":"109.2023%","Product":"Chocolate","Temperature":"14"}]';
$newAr = array();
foreach(json_decode($a,true) as $key=>$value)
{
$newAr[$value['Product']] = array(
'Level' => $value['Level'],
'Temperature' => $value['Temperature'],
);
}
There are many ways to perform this with Loops in PHP. Other answers demonstrate it accurately. I would also suggest to integrate some form of Error handling, data validation/filtering/restriction in your code to avoid unexpected results down the road.
For instance, json_decode(), either assigned to a variable pre-foreach or straight in the foreach() 1st argument will just raise a warning if the original json is not valid-json, and just skip over the foreach used to construct your final goal. Then if you pass the result (that may have failed) directly to your next logic construct, it could create some iffy-behavior.
Also, on the concept of data-validation & filtering, you could restrict the foreach(), or any other looping mechanism, to check against a Product_List_Array[Milk,Coffee,Chocolate], using if(in_array() ...) so the final/goal object only contains the expected Products, this, in the case the original json has other artifacts. Filtering the values can also increase stability in restricting, for example, Temperature to Float.

PHP Array: Assigning different keys to values

I know this is a simple concept (albeit one I struggle with) but I have some latitude and longitude data. It is read from a .data file (not as a .db, not my choice) and here is what I have so far:
$current_data = file("/my_data_file.data");
$latest_data = array();
foreach ($current_data as $entry)
{
$latest_data[] = $entry;
}
$latest_data = preg_replace("!\r?\n!", "", $latest_data);
echo json_encode($latest_data);
This outputs the data like so (didn't paste all of it here to save your eyes from bleeding):
["-118.510 33.896 ","-120.762 32.826 ","-122.959 31.716 ","-125.104 30.570 ","-127.198 29.389 ","-129.243 28.175 ","-131.243 26.931 ","-133.198 25.660 ","-135.112 24.362 ","-136.988 23.041 "]
So it's one giant array, each lat/long pair separated by a comma and each pair within quotations.
I've googled this and there is a ton of information on php arrays and key/values, but what's the right way to do it? I find myself making this much more complicated than it needs to be.
Assuming in the foreach loop it'll be something like
$latest_data[] = array('latitude' => $entry[the_lat_number], 'longitude' => $entry[the_long_number]);
Any input on the matter is appreciated.
Update: example of the data viewed in VIM (It doesn't visually appear there IS a whitespacing issue, but based on using explode, there does seem to be).
$current_data = file("/my_data_file.data");
$latest_data = array();
foreach ($current_data as $entry)
{
list($lat,$lng) = explode(" ",$entry);
$latest_data[] = array('lat' => $lat, 'lng' => $lng);
}
Now your json data should look something like this:
[{lat: xx, lng: xx},...]
Using your code to add each pair as subarray is good approach. This way you'll be able to easily access data from each row like that $latest_data[3]['latitude'] (to get latitude from fourth row).
Ok I ended up using preg_split instead of explode and all seems ok:
$current_data = file("/tmp/navhome/data/path_tail.data");
$latest_data = array();
foreach ($current_data as $entry) {
$coords = preg_split("/ +/", $entry);
$latest_data[] = array('latitude' => $coords[0], 'longitude' => $coords[1]);
}
echo json_encode($latest_data);
This is airplane data that gets updated when the flight path changes so it seemed preg_split was more appropriate.
This is outputting the data like so:
[{"latitude":"-118.510","longitude":"33.896"},{"latitude":"-120.762","longitude":"32.826"},{"latitude":"-122.959","longitude":"31.716"}]
Appreciate the input from everyone. Criticisms are welcome on this solution.

PHP Typecasting an Int as a String - doesn't seem to work as expected

I am trying to calculate percentiles for users in a database. In order to do this I have a $data array that I need to sort.
I have a query object that contains User_ID, Total_User_Orders, and Total_Orders. Here's how the code looks so far:
// Loop through the users
foreach($query->result() as $row)
{
(string)$user_id = (string)$row->user_id;
$data[$user_id] = number_format((($row->total_user_orders/$row->total_orders)*100), 5);
}
// Sort the $data array
array_multisort($data);
print_r($data);
What (I believe) that should do is typecast $row->user_id (an int) as a string. Then, the $data[$user_id] index should be set as a string - right...?
When I sort the array using array_multisort it sorts it as though the index was an Integer, rather than a String. This means it loses the index.
The PHP manual for array_multisort() states, "Associative (string) keys will be maintained, but numeric keys will be re-indexed.". I have also tried using array_multisort($data, SORT_STRING), but the same output occurs. However - it does work when I do $data['#'.$user_id], but this doesn't quite feel like the right solution to me!
Can anyone help? Thanks in advance!
I think you're overcomplicating things. With no testing, I'd think indexing the $data-array like this would work:
$data[(string)$row->user_id] = ...
or
$data[''.$user_id] = ...
EDIT:
Otherwise you could build your array multi-dimensional and sort by one of the indices, like this:
foreach($query->result() as $row) {
$data[] = array(
'user_id' => $row->user_id,
'percent' => number_format((($row->total_user_orders/$row->total_orders)*100), 5);
);
}
Or you could index by the percentage and sort by the keys (using ksort()):
foreach($query->result() as $row) {
$data[number_format((($row->total_user_orders/$row->total_orders)*100), 5)] = $row->user_id];
}
The last solution could be dangerous if several users have the same percentage.
Personally I would probably go with the asort() solution mentioned above.
As described in my comment, array_multisort() is not what you are after here. You don't have multiple arrays or a multi-dimensional array.
To maintain the key => value association in the array and sort the contents use asort().
foreach ($query->result() as $row) {
$percent = ($row->total_user_orders / $row->total_orders) * 100;
$data[$row->user_id] = number_format($percent, 5);
}
asort($data);
If you want descending percentages reverse the array after it's been sorted.
$data = array_reverse($data, true);

Programmatically Building an Associative Array

I am currently building a questionnaire system which spans over multiple steps (pages). I am using an assoc array which is stored in session to store the submitted answers.
I am having problems getting my head around how I would build this up programmatically.
The array should be as follows
array(STEP => array(ANSWER 1, ANSWER 2, ANSWER 3, etc...));
I have the step as a variable '$step' and the answer array is built up as a separate '$answers' variable.
So basically what I need to be able to build up is the following
array($step => $answers);
$_SESSION["answers"][$step] = array($ANSWER1, $ANSWER2, <other answers>);
It'd be up to you to define $step and the $ANSWERn variables, of course. And properly initializing your session, too.
After the questionnaire, you'd just step through your array to extract all the answers:
foreach($_SESSION["answers"] as $step => $answer) {
// magic happens here
}
(edit: I slightly modified the foreach to give you the $step variable)
$x = array();
$answer = array();
$answer[0]= "A 1";
$answer[1]= "A 2";
$x[$step] = $answer;

Autofill array with empty data to match another array size

I have 2 sets of arrays:
$dates1 = array('9/12','9/13','9/14','9/15','9/16','9/17');
$data1 = array('5','3','7','7','22','18');
// for this dataset, the value on 9/12 is 5
$dates2 = array('9/14','9/15');
$data2 = array('12','1');
As you can see the 2nd dataset has fewer dates, so I need to "autofill" the reset of the array to match the largest dataset.
$dates2 = array('9/12','9/13','9/14','9/15','9/16','9/17');
$data2 = array('','','12','1','','');
There will be more than 2 datasets, so I would have to find the largest dataset, and run a function for each smaller dataset to properly format it.
The function I'd create is the problem for me. Not even sure where to start at this point. Also, I can format the date and data arrays differently (multidimensional arrays?) if for some reason that is better.
You can do this in a pretty straightforward manner using some array functions. Try something like this:
//make an empty array matching your maximum-sized data set
$empty = array_fill_keys($dates1,'');
//for each array you wish to pad, do this:
//make key/value array
$new = array_combine($dates2,$data2);
//merge, overwriting empty keys with data values
$new = array_merge($empty,$new);
//if you want just the data values again
$data2 = array_values($new);
print_r($data2);
It would be pretty easy to turn that into a function or put it into a for loop to operate on your array sets. Turning them into associative arrays of key/value pairs would make them easier to work with too I would think.
If datas are related will be painful to scatter them on several array.
The best solution would be model an object with obvious property names
and use it with related accessor.
From your question I haven't a lot of hint of what data are and then I have to guess a bit:
I pretend you need to keep a daily log on access on a website with downloads. Instead of using dates/data1/data2 array I would model a data structure similar to this:
$log = array(
array('date'=>'2011-09-12','accessCount'=>7,'downloadCount'=>3),
array('date'=>'2011-09-13','accessCount'=>9), /* better downloadsCount=>0 though */
array('date'=>'2011-09-15','accessCount'=>7,'downloadCount'=>3)
...
)
Using this data structure I would model a dayCollection class with methods add,remove,get,set, search with all methods returning a day instance (yes, the remove too) and according signature. The day Class would have the standard getter/setter for every property (you can resolve to magic methods).
Depending on the amount of data you have to manipulate you can opt to maintain into the collection just the object data (serialize on store/unserialize on retrieve) or the whole object.
It is difficult to show you some code as the question is lacking of details on your data model.
If you still want to pad your array than this code would be a good start:
$temp = array($dates, $data1, $data2);
$max = max(array_map('count',$temp));
$result = array_map( function($x) use($max) {
return array_pad($x,$max,0);
}, $temp);
in $result you have your padded arrays. if you want to substitute your arrays do a simple
list($dates, $data1, $data2) = array_map(....
You should use hashmaps instead of arrays to associate each date to a data.
Then, find the largest one, cycle through its keys with a foreach, and test the existence of the same key in the small one.
If it doesn't exist, create it with an empty value.
EDIT with code (for completeness, other answers seem definitely better):
$dates_data1 = array('9/12'=>'5', '9/13'=>'3', '9/14'=>'7' /* continued */);
$dates_data2 = array('9/14'=>'12', '9/15'=>'1');
#cycle through each key (date) of the longest array
foreach($dates_data1 as $key => $value){
#check if the key exists in the smallest and add '' value if it does not
if(!isset( $date_data2[$key] )){ $date_data2[$key]=''; }
}

Categories