I access the following values like this.
$result->{'HistoricalPricesResult'}->HistoricalPricesResult[0]->Price
$result->{'HistoricalPricesResult'}->HistoricalPricesResult[0]->Low
//next row
$result->{'HistoricalPricesResult'}->HistoricalPricesResult[1]->Price
$result->{'HistoricalPricesResult'}->HistoricalPricesResult[1]->Low
However I need to consolidate this to
$values[0][price]
$values[0][low]
$values[1][price]
$values[1][low]
2 other strange things. The values are strings and I need them to be decimals(2 decimal points) and also the min and the max for price and low accross all the rows
Well the obvious way to build an array of values would be:
$values = array();
for($i = 0; $i < some_maximum_value; $i++) {
$values[$i] = array(
'price' => $result->{'HistoricalPricesResult'}->HistoricalPricesResult[$i]->Price,
'low' => $result->{'HistoricalPricesResult'}->HistoricalPricesResult[$i]->Low,
);
}
TADAAAAAA!!!!
$values = array();
foreach($result->{'HistoricalPricesResult'}->HistoricalPricesResult as $key => $obj){
$values[$key]['price'] = $obj->Price;
$values[$key]['low'] = $obj->low;
}
$myVals = array();
foreach ($result->{'HistoricalPricesResult'}->HistoricalPricesResult as $key => $v)
{
$myVals[$key]['price'] = 1.0 * $c->Price; //hoping string has 2 after the decimal
$myVals[$key]['low'] = 1.0 * $c->Low
}
Try to figure out max/min yourself
Check out foreach loops and string/float conversion
http://us2.php.net/manual/en/control-structures.foreach.php
http://www.php.net/manual/en/language.types.string.php#language.types.string.conversion
Related
Sorry for the title as it looks like most of the other questions about combining arrays, but I don't know how to write it more specific.
I need a PHP function, which combines the entries of one array (dynamic size from 1 to any) to strings in every possible combination.
Here is an example with 4 entries:
$input = array('e1','e2','e3','e4);
This should be the result:
$result = array(
0 => 'e1',
1 => 'e1-e2',
2 => 'e1-e2-e3',
3 => 'e1-e2-e3-e4',
4 => 'e1-e2-e4',
5 => 'e1-e3',
6 => 'e1-e3-e4',
7 => 'e1-e4'
8 => 'e2',
9 => 'e2-e3',
10 => 'e2-e3-e4',
11 => 'e2-e4',
12 => 'e3',
13 => 'e3-e4',
14 => 'e4'
);
The sorting of the input array is relevant as it affects the output.
And as you see, there should be an result like e1-e2 but no e2-e1.
It seems really complicated, as the input array could have any count of entries.
I don't even know if there is a mathematical construct or a name which describes such a case.
Has anybody done this before?
You are saying that there might be any number of entries in the array so I'm assuming that you aren't manually inserting the data and there would be some source or code entering the data. Can you describe that? It might be easier to directly store it as per your requirement than having an array and then changing it as per your requirement
This might be helpful Finding the subsets of an array in PHP
I have managed to bodge together a code that creates the output you want from the input you have.
I think I have understood the logic of when and why each item looks the way it deos. But Im not sure, so test it carefully before using it live.
I have a hard time explaining the code since it's really a bodge.
But I use array_slice to grab the values needed in the strings, and implode to add the - between the values.
$in = array('e1','e2','e3','e4');
//$new =[];
$count = count($in);
Foreach($in as $key => $val){
$new[] = $val; // add first value
// loop through in to greate the long incrementing string
For($i=$key; $i<=$count-$key;$i++){
if($key != 0){
$new[] = implode("-",array_slice($in,$key,$i));
}else{
if($i - $key>1) $new[] = implode("-",array_slice($in,$key,$i));
}
}
// all but second to last except if iteration has come to far
if($count-2-$key >1) $new[] = Implode("-",Array_slice($in,$key,$count-2)). "-". $in[$count-1];
// $key (skip one) next one. except if iteration has come to far
If($count-2-$key >1) $new[] = $in[$key] . "-" . $in[$key+2];
// $key (skip one) rest of array except if iteration has come to far
if($count-2-$key > 1) $new[] = $in[$key] ."-". Implode("-",Array_slice($in,$key+2));
// $key and last item, except if iteration has come to far
if($count-1 - $key >1) $new[] = $in[$key] ."-". $in[$count-1];
}
$new = array_unique($new); // remove any duplicates that may have been created
https://3v4l.org/uEfh6
here is a modificated version of Finding the subsets of an array in PHP
function powerSet($in,$minLength = 1) {
$count = count($in);
$keys = array_keys($in);
$members = pow(2,$count);
$combinations = array();
for ($i = 0; $i < $members; $i++) {
$b = sprintf("%0".$count."b",$i);
$out = array();
for ($j = 0; $j < $count; $j++) {
if ($b{$j} == '1') {
$out[] = $keys[$j];
}
}
if (count($out) >= $minLength) {
$combinations[] = $out;
}
}
$result = array();
foreach ($combinations as $combination) {
$values = array();
foreach ($combination as $key) {
$values[$key] = $in[$key];
}
$result[] = implode('-', $values);
}
sort($result);
return $result;
}
This seems to work.
I would post the entire code, but it is lengthly and confusing, so I'll keep it short and simple. This is complicated for myself, so any help will be greatly appreciated!
These are the values from my Array:
Light Blue1
Blue2
Blue1
Black3
Black2
Black1
The values I need to retrieve from my Array are "Light Blue1", "Blue2" and "Black3". These are the "highest values" for each color.
Something similar to what I'm looking for is array_unique, but that wouldn't work here. So something along those lines that can retrieve each color with its highest number.
Thanks!
Assuming your format is always NameNumber a regex should do the trick for separating the data. This will loop through your data in the order your provide and grab the first element that is different and put it into $vals. I am also assuming your data will always be ordered as your example shows
$data = ['Light Blue1',
'Blue2',
'Blue1',
'Black3',
'Black2',
'Black1'];
$vals = [];
$current = '';
foreach($data as $row) {
if(!preg_match('/(.*)(\d)/i', $row, $matched)) continue;
if($matched[1] != $current) {
$vals[] = $row;
$current = $matched[1];
}
}
The solution using preg_split and max functions:
$colors = ['Light Blue1', 'Blue2', 'Blue1', 'Black3', 'Black2', 'Black1'];
$unique_colors = $result = [];
foreach ($colors as $k => $v) {
$parts = preg_split("/(\d+)/", $v, 0, PREG_SPLIT_DELIM_CAPTURE);
$unique_colors[$parts[0]][] = (int) $parts[1];
}
foreach ($unique_colors as $k => $v) {
$result[] = $k . max($v);
}
print_r($result);
The output:
Array
(
[0] => Light Blue1
[1] => Blue2
[2] => Black3
)
If you pre-sort your array with "natural sorting", then you can loop through the array and unconditionally push values into the result with digitally-trimmed keys. This will effectively overwrite color entries with lesser number values and only store the the highest numbered color when the loop finishes.
Code: (Demo)
natsort($data);
$result = [];
foreach ($data as $value) {
$result[rtrim($value, '0..9')] = $value;
}
var_export(array_values($result));
Or you could parse each string and compare the number against its cached number (if encountered before): (Demo)
$result = [];
foreach ($data as $value) {
sscanf($value, '%[^0-9]%d', $color, $number);
if (!isset($result[$color]) || $result[$color]['number'] < $number) {
$result[$color] = ['value' => $value, 'number' => $number];
}
}
var_export(array_column($result, 'value'));
A related technique to find the highest value in a group
I'm making a simple search engine, and I have already indexed a lot of websites in a MySQL database. Now I would like to get a relevant list of results by keywords.
Websites are indexed in my database with the following columns : hostname (without protocol an port), title, description. (We don't care about path)
When I type some keywords on my search engine homepage, it first starts by fetching 50 websites using FULLTEXT indexes.
Now, and because using Levenshtein algorithm in MySQL is really slow, I would like to sort those results with the Levenshtein PHP function for each columns I listed previously.
I would like to sort them in this order (most important first) : hostname, title, and then description.
So I have five arrays :
$results, returned by MySQL
$sorted_by_mysql, containing keys of $results in the original order : 0, 1, 2, ...
$sorted_by_hostname, containing keys of $results sorted by hostname's relevance using Levenshtein, ex: 3, 0, 1, 2, ...
$sorted_by_title, containing keys of $results sorted by title's relevance using Levenshtein, ex: 0, 2, 1, 3, ...
$sorted_by_description, containing keys of $results sorted by description's relevance using Levenshtein, ex: 1, 3, 0, 2, ...
Here's the code :
$results = $req->fetchAll();
$search = strtolower($q);
$temp_arr = [];
$sorted_by_mysql = $sorted_by_hostname = $sorted_by_title = $sorted_by_description = [];
// We keep the original order in an array
for($i = 0; $i < count($results); $i++) $sorted_by_mysql[] = $i;
// Sort by hostname
for($i = 0; $i < count($results); $i++) $temp_arr[$i] = levenshtein($search, strtolower($results[$i]->hostname));
asort($temp_arr);
foreach($temp_arr as $k => $v) $sorted_by_hostname[] = $k;
// Sort by title
for($i = 0; $i < count($results); $i++) $temp_arr[$i] = levenshtein($search, strtolower($results[$i]->title));
asort($temp_arr);
foreach($temp_arr as $k => $v) $sorted_by_title[] = $k;
// Sort by description
for($i = 0; $i < count($results); $i++) $temp_arr[$i] = levenshtein($search, strtolower($results[$i]->description));
asort($temp_arr);
foreach($temp_arr as $k => $v) $sorted_by_description[] = $k;
Finally I would like to sort $results by combining (by priority) all thoses different arrays. But I have no idea on how, so here's where I need some help !
EDIT : Solution !
$data = $req->fetchAll();
$search = strtolower($q);
$temp = [];
foreach($data as $i => $row) {
$temp[] = [
'id' => $i,
'lev1' => levenshtein($search, strtolower($row->hostname)),
'lev2' => levenshtein($search, strtolower($row->title)),
'lev3' => levenshtein($search, strtolower($row->description))
];
}
$sorted = array_orderby($temp, 'lev1', SORT_ASC, 'lev2', SORT_ASC, 'lev3', SORT_ASC, 'id', SORT_ASC);
$results = [];
foreach($sorted as $row) {
$results[] = $data[$row['id']];
}
// Perfectly sorted !
Here's array_orderby function :
// Credits : jimpoz at jimpoz dot com (PHP.net)
function array_orderby()
{
$args = func_get_args();
$data = array_shift($args);
foreach ($args as $n => $field) {
if (is_string($field)) {
$tmp = array();
foreach ($data as $key => $row)
$tmp[$key] = $row[$field];
$args[$n] = $tmp;
}
}
$args[] = &$data;
call_user_func_array('array_multisort', $args);
return array_pop($args);
}
See the answer to this SO question, they have a similar need but have structured their data in a way that makes the answer easier. It looks like PHP supports sorting by multiple attributes (in descending priority) as long as those attributes are built into the associative array that's being sorted.
To apply this approach to your data, you'll probably want to restructure your results into one giant associative array where each element of the array contains a value for each "field" you're aiming to sort by. Does that make sense?
Good luck!
I have code that will make an array or arrays of UNKNOWN length because it depends on how many new people have been added to the mysql DB. (this is where I'm getting confused)
The array has $x items, each item is an array of first name, last name, and e-mail address.
I want the loop to run till the array is ended.
$x = 0;
while($array[$x]['per_LastName'] != 'NULL') {
$batch[] = array('EMAIL'=>$array[$x]['per_Email'], 'FNAME'=>$array[$x]['per_FirstName'], 'LNAME'=>$array[$x]['per_LastName']);
$x = $x+1;
}
apparently I'm looping infinity because it uses all the memory.
Use a foreach loop which will loop through all elements of the array.
foreach($array as $key => $value) {
$batch[] = array('EMAIL'=>$value['per_Email'], 'FNAME'=>$value['per_FirstName'], 'LNAME'=>$value['per_LastName']);
}
Instead you should use a for loop
for($x = 0; $x<count($array); $x++){
$batch[] = array('EMAIL'=>$array[$x]['per_Email'], 'FNAME'=>$array[$x]['per_FirstName'], 'LNAME'=>$array[$x]['per_LastName']);
}
why not use foreach and avoid counters and unnecessary checks?
foreach($array as $eachArray)
{
$batch[] = array('EMAIL'=>$eachArray['per_Email'], 'FNAME'=>$eachArray['per_FirstName'], 'LNAME'=>$eachArray['per_LastName']);
}
i have a array that returns some numbers. and i want to add those numbers together and also count them.
here is what i have so far:
<?php
$homepage = file_get_contents('http://graph.facebook.com/215844978437619/reviews');
$parsed = json_decode($homepage,true);
foreach ($parsed['data'] as $key => $values){
$totalRatings1 = $values['rating'] ;
}
?>
what i am trying to do is to sum the $values['rating'] together and also count them.
So that: $totalRatings = sum_array($values['rating']) and $totalCount = count($values['rating'])
but i get lost in the sintax.
any ideas?
Thanks
<?php
$homepage = file_get_contents('http://graph.facebook.com/215844978437619/reviews');
$parsed = json_decode($homepage,true);
$totalRatings = 0;
$totalRated = 0;
foreach ($parsed['data'] as $key => $values){
$totalRatings += (int) $values['rating'];
$totalRated++;
}
?>
$totalRatings will have the aggregated sum of all ratings, $totalRated will be the count of how many ratings there are.
Just declare two variables and then increment them on each iteration:
<?php
$homepage = file_get_contents('http://graph.facebook.com/215844978437619/reviews');
$parsed = json_decode($homepage,true);
$totalRating = 0;
$totalItems = 0;
foreach ($parsed['data'] as $key => $values) {
$totalRating += $values['rating'];
$totalItems++;
}
$totalRating will hold the sum of all rating while $totalItems will contain the total number of items.