Complicated array operation - php

I have a pretty complicated array operation, or at least it is complicated for me. Lets say I got such kind of array
$myArr['url_1']['linktypes']['follow'] = 10;
$myArr['url_1']['linktypes']['nofollow'] = 20;
$myArr['url_1']['linktypes']['other'] = 30;
$myArr['url_2']['linktypes']['follow'] = 40;
$myArr['url_2']['linktypes']['nofollow'] = 50;
$myArr['url_2']['linktypes']['other'] = 60;
$myArr['url_3']['linktypes']['follow'] = 70;
$myArr['url_3']['linktypes']['nofollow'] = 80;
$myArr['url_3']['linktypes']['other'] = 90;
and simply (!) I need to get following result
array(
array("id"=>1,"metric"=>'follow','url_1'=>10,'url_2'=>40,'url_3'=>70),
array("id"=>2,"metric"=>'nofollow','url_1'=>20,'url_2'=>50,'url_3'=>80),
array("id"=>3,"metric"=>'other','url_1'=>30,'url_2'=>60,'url_3'=>90)
);
These array elements are created dynamicall from $myArr. I have tried many ways but I failed many times. Hopefully someone has a short, simple logic to solve this.
Thanks.
Edit: This one is my shortest try. I have many different ways but this code is a part of big code structure, example you see here is created to simplify the logic I need.
$linkStructure = array();
foreach($myArr as $links=>$value){
$counter = 0;
foreach($value['linktypes'] as $ltKey => $ltValue){
if($linkStructure[$counter]["id"] && $linkStructure[$counter]["metric"] == $ltKey){
$linkStructure[$counter][$links] = $ltValue;
}
else{
$linkStructure[$counter]["id"] = $counter;
$linkStructure[$counter]["metric"] = $ltKey;
$linkStructure[$counter][$links] = $ltValue;
}
}
}
I swear I tried how I can prove better I don't know. Don't torture please. If you have any idea just share, is it too much I'm asking for?

I can't explain this very well, so I'm just going to use code:
$fixedArr = array();
$idCount = 1;
foreach($myArr as $title=>$subArr)
foreach($subArr['linktypes'] as $metric=>$val) {
if(!array_key_exists($metric)) {
$fixedArr[$metric] = array();
$fixedArr[$metric]['id'] = $idCount;
$fixedArr[$metric]['metric'] = $metric;
$idCount += 1;
}
$fixedArr[$metric][$title] = $val;
}
That should do it.
But I should say that the comments are right, a better way to structure your array would be like this:
Array {
[url_*] => Array {
[metric] => someValue;
}
}
Basically the same way you have it originally, but with fewer dimensions. This is all that you need for the data you have provided.

Related

SolrClient In PHP. How to update a documents in Apache Solr with big amount of SolrInputDocuments

I using SolrClient for PHP and I ran into one problem when inserting a lot of data.
This is my script:
$doc = [];
$obj_client = new SolrClient($this->options);
$cityResult = $result_city_array->result(); // number over 37 000
$n = 0;
foreach ($cityResult as $row) {
$doc[$n] = new SolrInputDocument();
$doc[$n]->addField('id', $row->id);
$doc[$n]->addField('country_id', $row->country_id);
$doc[$n]->addField('country', $row->country_name);
$doc[$n]->addField('city_id', $row->city_id);
$doc[$n]->addField('city_name', $row->city_name);
$n++;
}
if (!empty($doc)) {
$obj_client->addDocuments($doc);
$obj_client->commit();
}
In the foreach loop, the script breaks due to the large amount of documents(more than 37000). Maybe someone came across similar and knows what optimal number of documents should be for one commit?
For example(something like this):
if (count($doc) === 1000) {
$obj_client->addDocuments($doc);
$obj_client->commit();
$doc = [];
$n = 0;
//Next row is question too
$obj_client = new SolrClient($this->options); //Should I refresh SolrClient entity????
}
Thanks in advance!

JSON array unset

First of all, I really don't know if that kind of topic exist. But I searched a lot and now I am here.
My question about parsing. For example I would like to unset some items.
$now = array();
$now[0]['name'] = "Hello1";
$now[0]['si'] = "BumBum1";
$now[1]['name'] = "Hello2";
$now[1]['si'] = "BumBum2";
$now[2]['name'] = "Hello3";
$now[2]['si'] = "BumBum3";
$now[3]['name'] = "Hello4";
$now[3]['si'] = "BumBum4";
echo json_encode($now)."<br>";
unset($now[0]);
echo json_encode($now);
And the output:
[{"name":"Hello1","si":"BumBum1"},{"name":"Hello2","si":"BumBum2"},{"name":"Hello3","si":"BumBum3"},{"name":"Hello4","si":"BumBum4"}]
{"1":{"name":"Hello2","si":"BumBum2"},"2":{"name":"Hello3","si":"BumBum3"},"3":{"name":"Hello4","si":"BumBum4"}}
And my the JSON file turns to messy code. Appears numbers and etc.
Any ideas how to solve this.
You need to "reindex" the array (use array_values() function).
//unset..
unset($now[0]);
//reindex
$now = array_values($now);
//display as before
echo json_encode($now);

array_filter for making breadcrumb

I wrote a simple function (copied and adapted, more like it!) to make breadcrumb for one application. My folder structure is such that if some folders are ignored, the trail would still work. I have looked it for far too long with no progress ...
function breadCrumb(){
// folders to ignore
$filterFolders = array('360', 'files');
if($location = substr(dirname($_SERVER['PHP_SELF']), 1)){
$dirlist = explode('/', $location);
}else{
$dirlist = array();
}
/** update the array with non required folders **/
$filteredArr = array_diff_key($dirlist, array_flip($filterFolders));
$count = array_push($filteredArr, basename($_SERVER['PHP_SELF']));
$address = 'http://'.$_SERVER['HTTP_HOST'];
echo 'Home';
for($i = 0; $i < $count; $i++){
echo ' ยป '.ucfirst($filteredArr[$i]).'';
}
}
Thanks in advance, any help would be much appreciated!
I don't see any use of array_filter in your code, contrary to what's suggested by the question title. However, You should be running the difference function on values, not on keys (because you didn't specify any) in this case.
Hence
$filteredArr = array_diff_key($dirlist, array_flip($filterFolders));
^
Should be
$filteredArr = array_diff($dirlist,$filterFolders); // you don't even ve to flip
For example
$filterFolders = array('360', 'files');
What would you expect those keys to be? they are 0 for the value 360 and 1 for the value 'files', so checking the difference of keys won't do what's expected.

Cannot use string offset as an array (What does it mean?)

The code below is more or less a chunk of my code. The $servername and $monthlyincome variables are not actually static as shown here but I changed them so I could add less code here.
If I run this code...
$servername="Server1";
$months = array('January','February','March','April','May','June','July','August','September','October','November','December');
for ($i=0;$i<=24;$i++) {
$new_time = mktime(0,0,0,date("m")+$i,1,date("Y"));
$months_array[date("Y",$new_time)][date("m",$new_time)] = "x";
}
$overallincome = 0;
foreach ($months_array AS $year=>$month) {
foreach ($month AS $mon=>$x) {
$monthlyincome = 3;
$overallincome += $monthlyincome;
$$servername[$months[$mon-1]." ".$year]['monthlyincome']=$monthlyincome;
$$servername[$months[$mon-1]." ".$year]['overallincome']=$overallincome;
}
}
I get this error...
Cannot use string offset as an array in on line 123
Line 123 is this line... $$servername[$months[$mon-1]." ".$year]['monthlyincome']=$monthlyincome;
I can't figure out what I am doing wrong. I have checked other posts on SO with the same error but nothing made sense to me.
Putting it as an answer, then!
$$servername[] seems to be the problem. It's interpreting it as ${$servername[]} where you want it to interpret as ${$servername}[].
Try putting those curly-brackets in there and see if that helps.

Can any one give me some advice to make my for loop more efficient?

So I have this for loop with 36 if-queries inside. Any advice on making it more efficient?
You can view the complete code here
Here's a sample of what it looks like:
$numbers = range(1, 36);
shuffle($numbers);
for ($m =0; $m<37; $m++){
if ($numbers[$m] == "1"){
$mirza[$m] = "RUTHIE";
$mage[$m] = "3";
$mquote[$m] = "I get to learn a lot of new things here, like sign language!";
$link[$m] = "http://www.google.com";
}
if ($numbers[$m] == "2"){
$mirza[$m] = "AIDA";
$mage[$m] = "82";
$mquote[$m] = "This is like a club and I know and like all the members. It's good therapy.";
$link[$m] = "/about/";
}
if ($numbers[$m] == "3"){
$mirza[$m] = "AMIRE";
$mage[$m] = "4";
$mquote[$m] = "I am learning how to share and make friends.";
$link[$m] = "/about/";
}
}
Changing your if-s to a switch with appropriate breaks or even at worse if..elseif..etc would mean that not all ifs have to be evaluated.
When you have this much data it really should be in a database (maybe XML or document style) or a text file.
Still, I'll show you a way to improve this by hard-coding all the data in one place and eliminating the need for any if or switch statements. You should AT VERY LEAST change to switch statements, better still hard-code all the data in one place (below), better still get a database or CSV text file storing these values.
$data = array(
array('mirza' => 'RUTHIE', 'mage' => '3', 'mquote' => 'I get to learn a lot of new things here, like sign language!', 'link' => 'http://www.google.com'),
array(......
);
$numbers = range(1, 36);
shuffle($numbers);
for ($m =0; $m<37; $m++){
$index = $numbers[$m];
$mirza[$m] = $data[$index]['mirza'];
$mage[$m] = $data[$index]['mage'];
$mquote[$m] = $data[$index]['mage'];
$link[$m] = $data[$index]['link'];
}
Just to be clear, the 'efficiency' issue here isn't so much speed (though this way is faster). Its that what you have is a nightmare to maintain and change.
You might do better to seriously reconsider the design of your app, specifically making an object with mirza, mage, mquote, link as fields.
Is your problem that you feel you simply have too many "if" statements? Try a switch statement. Technically speaking, your loop is about as efficient as possible (using big-O method of evaluating efficiency).
for ($m =0; $m<37; $m++){
switch($numbers[$m])
{
case 1:
$mirza[$m] = "RUTHIE";
$mage[$m] = "3";
$mquote[$m] = "I get to learn a lot of new things here, like sign language!";
$link[$m] = "http://www.google.com";
break;
case 2:
$mirza[$m] = "AIDA";
$mage[$m] = "82";
$mquote[$m] = "This is like a club and I know and like all the members. It's good therapy.";
$link[$m] = "/about/";
break;
case 3:
$mirza[$m] = "AMIRE";
$mage[$m] = "4";
$mquote[$m] = "I am learning how to share and make friends.";
$link[$m] = "/about/";
break;
}
}
My guess it's already as fast as you may ever need.
The only way to make it faster is to look at sites benchmarking PHP and to adjust this or that to easy the most efficent PHP internals.
Since PHP internals may change over time (with PHP updates), unless you regulary benchmark your code I'd say you have not that much to gain, especially with code that simple.
For example you may try to change
$numbers[$m] == "2"
with
$numbers[$m] === 2
or
$numbers[$m] === "2"
But if you don't benchmark your code (ex. putting it in a function and measure the execution time over 10.000 iterations) you're gonna be blind about improvements. PHP internals speed don't always behave as you expect it.
(the same goes with the answer you got about the switch statement. Try it, but benchmark !)
My advice is to try to work with data structures, and put all these values in an array of the same type as the data structure. That way, if you later need to access the values again with the same number-to-value relationship, you won't have to redefine everything like you have done here. All you would have to do then is to use array indices to access the values.

Categories