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]=''; }
}
Related
I need to check some input string against a huge (and growing) list of strings coming from a CSV file (1000000+). I currently load every string in an array and check against it via in_array(). Code looks like this:
$filter = array();
$filter = ReadFromCSV();
$input = array("foo","bar" /* more elements... */);
foreach($input as $i){
if(in_array($i,$filter)){
// do stuff
}
}
It already takes some time and I was wondering is there is a faster way to do this?
in_array() checks every element in the array until it finds a match. The average complexity is O(n).
Since you are comparing strings, you might store your input as array keys instead of values and look them up via array_key_exists(); which requires a constant time O(1).
Some code:
$filter = array();
$filter = ReadFromCSV();
$filter = array_flip($filter); // switch key <=> value
$input = array("foo","bar" /* more elements... */);
foreach($input as $i){
if(array_key_exists($i,$filter)){ // array_key_exists();
// do stuff
}
}
That's what indexes were invented for.
It's not a matter of in_array() speed, as the data grows, you should probably consider using indexes by loading data into a real DBMS.
I'm using PHP to retrieve data from an SQL database to produce a stacked column chart in Highcharts. The idea is that I'm taking the following piece of code to retrieve values from my database. This code should generate an array which then gets encoded to JSON and passed to Highcharts; this code produces a single 'part' of a stacked column, and the index determines which vertical bar that part is in. (So in http://www.highcharts.com/demo/column-stacked, the index would represent which fruit, and the data in this series would represent one person/color.)
The issue is that when I run this code, instead of ending up with an indexed array of data grouped by category, such as
[12,13,14,15] where each item is a category, I end up with an associative array where the indexes I specified in the code are turned into a string key.
{"1":13,"0":12,"3":14, "2":13, "5":15}
Because my indexes are being interpreted as associative keys and not as the indexed locations of the data inside the array, the data is now being added to locations in the order that I retrieved the data, and not assigned to a location in the array based on the index I give. Highcharts assigns categories based on location in the array, and not on key, so all my data ends up in the wrong categories.
Is there a way to get PHP to treat my carefully collected indexes as indexes and not as keys, and add my data points in the location in the array indicated by the indexes? I'm kind of new to PHP, and Java and C++ - the languages I've worked with before - don't have associative arrays, so any help you can give me in explaining and fixing this undesired behavior would be much appreciated.
Code below.
$variable indicates what the data is being sorted into categories by, and $r is the variable representing the array of the SQL query, so $r['variable'] is the category of this data point, and $r['amount'] is the data point itself.
$found = -1;
//if this is the first set of data being collected
if (count($category['data']) == 0){
$category['data'][0] = $r[$variable];
$series1['data'][0] = floatval($r['amount']);
$count++;
$times1[0]++;
}
//if it's not the first set of data, find out if this category has been used before
else {
for ($x = 0; $x < count($category['data']); $x++){
if ($r[$variable] == $category['data'][$x]){
$found = $x;
break;
}
}
// if that category does not already exist, add it, and add the data
if ($found == -1) {
$times1[$count]++;
$category['data'][$count] = $r[$variable];
$series1['data'][$count] = floatval($r['amount']);
$count++;
}
else { //otherwise, add its data to the data already in the current category. This will eventually yield an average, with $times1[] as the divisor
$times1[$found]++;
$series3['data'][$found] = floatval((floatval($series3['data'][$found]) + floatval($r['amount'])));
}}
Go through with below code hope it will give some idea to resolve your problem --
<?php
$jsonstring = '{"1":13,"0":12,"3":14, "2":13, "5":15}';
$tempArr = json_decode($jsonstring, true);
asort(tempArr); // for sorting the array --
//run another foreach to get created an array --
$finArr = array();
foreach(tempArr as $key=>$val){
$finArr[] = $val;
}
$requiredjsonString = json_encode(finArr); // it will return your required json Array [12,13,14,15]
?>
Edit: I advice also set JSON_NUMERIC_CHECK flag in json_encode();
Is there any way to maintain a sorted array of objects?
For example, if I have an object with properties ID, Date, Name and a collection of these objects:
$col = array();
public function addNewObject($id, $date, $name)
{
$col[] = new Object($id, $date, $name);
//but instead of appending, it should place it by Name desc
}
If I call something like getObjects, it would return the items in the collection by Name desc.
I think there were some answers for getting objects back in a sorted order, but for efficiency, I would think it be better to sort at insert as the "sort by" variable in my case will never change.
UPDATE:
So based on the comments, I should resort the whole array each time something is added but that seems a bit memory intensive...
Since the array would always be in sorted order to start out with I can identify the location where I want to insert by traversing the array (would this be efficient, is there a better way?). Once I find that how could I "insert" a new object into the array?
I do not imagine that the array will be very large but I would like to implement this the most efficient way possible.
If you're not keen on resorting the array after you add (although I'd recommend it; realistically this wont be a performance issue and it keeps the code readable.
However, if you definitely don't want to do this then you can, as you said, traverse the array and find out where to insert:
$col = array();
public function addNewObject($id, $date, $name){
//Find the index to insert at
$index = 0;
foreach($col as $i => $item){
if($item->name > $name){
//This item is after the item we want to insert.
//Use the previous index and stop traversing
break;
}
$index = $i;
}
$col = array_splice($col, $index, 0, new Object($id, $date, $name));
}
Using array_splice to insert at an arbritary position thanks to https://stackoverflow.com/a/3797526/505722
this is a good example of a function that sorts an array from whatever key you want it sorted by
http://www.php.net/manual/en/function.sort.php#99419
in your example you should run it like :
array_sort($col, 'Name', SORT_DESC));
take in mind that every time you add a new item to the array the whole array is sorted each time
I've done a fair bit of googling and couldn't find anything that works, I'm just getting nothing back, this is probably something simple but there's a lot of variations that don't seem to match what I'm doing.
To give you an overall idea what I'm at, I'm accessing an API and getting back info as an object. There are comments and attachments, these are in separate arrays.
What i want to do is display the comments and attachments all together in the order of the date and time not separately.
I figured the best way is to create a loop through the comments array, then create a loop through the attachment array, then join both and sort by the date (epoch) and then loop through the whole merged loop echoing what i want. That should provide some context, right now i just want to create the multidimensional array for comments and i can figure out the rest.
$comments_holder = array();
//total number of comments in the array
$comment_total = $issue_json->fields->comment->total -1;
$i=1;
while ($i <= $comment_total)
{
//this is the date,time and timezone info for each comment
$raw_date = $issue_json->fields->comment->comments[$i]->updated;
$comments_holder[$i] = array();
//convert_sql_time just converts from 2012-11-04T16:33:00.936+600 into epoch time so i can sort the results later based on date
$comments_holder[$i]['comments_date'] = convert_sql_time($raw_date);
$comments_holder[$i]['comments_displayName'] = $issue_json->fields->comment->comments[$i]->author->displayName;
$comments_holder[$i]['comments_body'] = $issue_json->fields->comment->comments[$i]->body;
}
if everything is okay with data, this code will be enough for building such array:
$comments = $issue_json->fields->comment->comments;
$result = array();
foreach ($comments as $comment) {
$result[] = array(
'comments_date' => convert_sql_time($comment->updated),
'comments_displayName' => $comment->author->displayName,
'comments_body' => $comment->body,
);
}
print_r($result);
if comment->comments is an array, there is no need to keep it's count separately;
foreach is enough for iterating through the array and there is no need to keep separate variable for calculating array index;
[] notation will automatically increase array index and assigning array directly will do the trick(i.e. will result to multi dim array)
I am taking over a large project, and a lot of nested arrays are defined for option select lists to be used with form_dropdown() and form_multiselect() in Codeigniter. However, these arrays simply have values set and not corresponding keys.
Here's an example:
$lists['roomItems'] = array('Private telephone','Television cable/satellite','Personal furniture/decorations','Computer','Radio');
$lists['busRoute'] = array('Yes','No');
$lists['transport'] = array('Medical appointments','Dental appointments','Dialysis center','Wound care center','Religious services',
'Shopping services');
What I'd like to do is recursively go through $lists and make the keys equivalent to the values. For a single array, I tried foreach($lists['roomItems'] as $key=>value) and tried setting the key equal to the value, but it didn't take.
Can anyone help? I have about 30 items in the $lists array plus other ones that I'd re-use this code, so simply manually changing the pointers isn't really something I'd like to do. Thanks!
mhmmm what about:
$newList = array();
foreach($lists as $k=>$v) $newList[$k] = array_combine($v,$v);
should do the trick