associative array to nested set - php

I am trying to get nested set data for an associative array. The array needs to be stored as a nested set in mysql database. Array i want to get nested set data for:
Link for nested set implementation
http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
Array
(
[NEOPLASMS OF MATURE T CELLS OR NK CELLS] => Array
(
[Adult T-cell leukemia/lymphoma] => Array
(
[1] => Helper T cell
[2] => HTLV-1 provirus present in tumor cells
[3] => Adults with cutaneous lesions, marrow involvement, and hypercalcemia; occurs mainly in Japan, West Africa, and the Caribbean; aggressive
)
[Peripheral T-cell lymphoma, unspecified] => Array
(
[4] => Helper or cytotoxic T cell
[5] => No specific chromosomal abnormality
[6] => Mainly older adults; usually presents with lymphadenopathy; aggressive
)
[Anaplastic large-cell lymphoma] => Array
(
[7] => Cytotoxic T cell
[8] => Rearrangements of ALK
[9] => Children and young adults, usually with lymph node and soft-tissue disease; aggressive
)
[Extranodal NK/T-cell lymphoma] => Array
(
[10] => NK-cell (common) or cytotoxic T cell (rare)
[11] => EBV-associated; no specific chromosomal abnormality
[12] => Adults with destructive extranodal masses, most commonly sinonasal; aggressive
)
[Mycosis fungoides/Sézary syndrome] => Array
(
[13] => Helper T cell
[14] => No specific chromosomal abnormality
[15] => Adult patients with cutaneous patches, plaques, nodules, or generalized erythema; indolent
)
[Large granular lymphocytic leukemia] => Array
(
[16] => Two types: cytotoxic T cell and NK cell
[17] => No specific chromosomal abnormality
[18] => Adult patients with splenomegaly, neutropenia, and anemia, sometimes, accompanied by autoimmune disease
)
)
)
Array output i want:
Array
(
[0] => Array
(
[0] => NEOPLASMS OF MATURE T CELLS OR NK CELLS
[1] => 1
[2] => 26
)
[1] => Array
(
[0] => Adult T-cell leukemia/lymphoma
[1] => 2
[2] => 9
)
.............. and so on.
)
Here is where I am stuck at:
class nested_data
{
var $nc = 1;
var $map;
var $nest = array();
function make_nest()
{
array_walk($this->map, array($this,"fetch_nest_data"));
foreach($this->map as $map)
{
array_walk($map,array($this,"fetch_nest_data"));
}
}
function fetch_nest_data($val,$key)
{
$content = (is_array($val)) ? $key : $val;
$lft = $this->nc++;
$rgt= (is_array($val)) ? (count($val, COUNT_RECURSIVE) + $this->nc) : $this->nc++;
$this->nest[]=array($content,$lft,$rgt);
}
}
Thank you for your help !

What I've done is make a nested set manager which has methods or functions like addChild(), addSibling(), moveNodeUp(), moveNodedown(), setNodePosition(). From there you can just loop through an array, text file representation, whatever and turn them into a nested set pretty quickly. The hardest part is breaking apart all the little node movements.

Related

PHP Nested foreach with Key

I have been trying to work this out for two days now and am hitting a brick wall. I have a skyscanner array that has flight itineraries where I have the flight
Leg - being Itineraries -> OutboundLegId -
and also the legs which shows the flight number - being
Legs -> FlightNumbers -> FlightNumber.
What I am trying to achieve is to display the Itinerary and then join the Flight Number on to that. But no matter what I try I cannot get this to work. I have read all about Keys on here and tried loads of examples but am coming up with nothing. Can someone point me in the right direction please?
Example arrays below
[Itineraries] => Array
(
[0] => Array
(
[OutboundLegId] => 13542-1610140610-29-0-13445-1610141240
[InboundLegId] => 13445-1610211340-29-0-13542-1610211640
[PricingOptions] => Array
(
[0] => Array
(
[Agents] => Array
(
[0] => 2174187
)
[QuoteAgeInMinutes] => 31
[Price] => 200.98
[DeeplinkUrl] => http://partners.api.skyscanner.net/apiservices/deeplink/v2?_cje=5JlLCgyPUKY0hT8T0Ybh6dL0Xf0htAiHTFX7RU79eeI3XvrsxvEqP1QUJAoHiHRd&url=http%3a%2f%2fwww.apideeplink.com%2ftransport_deeplink%2f4.0%2fUK%2fen-gb%2fGBP%2fcook%2f2%2f13542.13445.2016-10-14%2c13445.13542.2016-10-21%2fair%2fairli%2fflights%3fitinerary%3dflight%7c-32294%7c1152%7c13542%7c2016-10-14T06%3a10%7c13445%7c2016-10-14T12%3a40%2cflight%7c-32294%7c1153%7c13445%7c2016-10-21T13%3a40%7c13542%7c2016-10-21T16%3a40%26carriers%3d-32294%26passengers%3d1%2c0%2c0%26channel%3ddataapi%26cabin_class%3deconomy%26facilitated%3dfalse%26ticket_price%3d200.98%26is_npt%3dfalse%26is_multipart%3dfalse%26client_id%3dskyscanner_b2b%26request_id%3d3bc96bda-fd7c-403a-b841-2ccc3c26071d%26commercial_filters%3dfalse%26q_datetime_utc%3d2016-09-29T08%3a18%3a27
)
[Legs] => Array
(
[0] => Array
(
[Id] => 13542-1610140610-29-0-13445-1610141240
[SegmentIds] => Array
(
[0] => 1
)
[OriginStation] => 13542
[DestinationStation] => 13445
[Departure] => 2016-10-14T06:10:00
[Arrival] => 2016-10-14T12:40:00
[Duration] => 270
[JourneyMode] => Flight
[Stops] => Array
(
)
[Carriers] => Array
(
[0] => 105
)
[OperatingCarriers] => Array
(
[0] => 105
)
[Directionality] => Outbound
[FlightNumbers] => Array
(
[0] => Array
(
[FlightNumber] => 1152
[CarrierId] => 105
)
)
)
Assuming this is one big array and its called $data you can nest a couple of foreach loops.
I use foreach loops as I assume there are cases where this data structure get more complex than the one you show
foreach ( $data['Itineraries'] as $itin ) {
foreach ( $data['Legs'] as $legs) {
if ($legs['Id'] == $itin['OutboundLegId']) {
// we matched the itinerary with a leg
echo $legs['OutboundLegId'] . ' ' . $legs['FlightNumbers'][0]['FlightNumber'];
}
}
}
Use it as draft. Can't perform function without feedback.
Put proper arrays instead of {YOUR-ARRAY-WITH-LEGS} and {YOUR-ARRAY-WITH-ITINERARIES}
$sortedLegs = array_column('Id', {YOUR-ARRAY-WITH-LEGS});
$joinedArray = array_map(function($itinerary) use($sortedLegs){
if(array_key_exists($itinerary['OutboundLegId'],$sortedLegs)) {
$itinerary['legs'] = $sortedLegs[$itinerary['OutboundLegId']];
}
return $itinerary;
},{YOUR-ARRAY-WITH-ITINERARIES});

Arrange array and delete duplicate values

I'm stuck with a tricky task I can't solve without the code being very messy with a lot of foreach loops.
This is the fundamental logic:
There can only be unique foods in the array, so only one guy can have Pizza, only one guy can have Pasta etc. But they can have multiple foods. And the guy with the most foods in the array, should win the foods over the ones with few foods.
So John should be deleted from the array since either Joe or Conny will have his.
And since Joe and Conny have the same amount of foods, one of them will keep all of his foods and the other one should be deleted from the array and it should be picked randomly whether it is Joe or Conny.
The starting array looks like this:
Array
(
[Joe] => Array
(
[0] => Pizza
[1] => Pasta
[2] => Lasagne
[3] => Tacos
[4] => Hamburger
)
[Conny] => Array
(
[0] => Pizza
[1] => Pasta
[2] => Lasagne
[3] => Tacos
[4] => Hamburger
)
[John] => Array
(
[0] => Pizza
[1] => Pasta
)
[Fred] => Array
(
[0] => Pizza
[1] => Pasta
[2] => Soup
[3] => Fish
)
[Greg] => Array
(
[0] => Sushi
)
)
And the end result I want is:
Array
(
[Joe] => Array
(
[0] => Pizza
[1] => Pasta
[2] => Lasagne
[3] => Tacos
[4] => Hamburger
)
[Fred] => Array
(
[2] => Soup
[3] => Fish
)
[Greg] => Array
(
[0] => Sushi
)
)
So only unique foods left in the array and if two or more guys have the same amount, it should randomly pick whether of these should keep the foods.
Any suggestions how I can do this?
You have to first sort the array depending on the count of elements in the subarray in reverse order using an user-defined function with uasort. Then you can use two foreach loops to loop through the loop. You will use a helper variable to determine if a food has already been used and if so unset the element. After doing that you filter out the empty elements in the array with array_filter.
uasort($food, function($a, $b) {
return count($b) <=> count($a);
});
$used = array();
foreach($food as $kl => $pl) {
foreach($pl as $k => $p) {
if(!in_array($p, $used)) {
$used[] = $p;
} else {
unset($food[$kl][$k]);
}
}
}
$food = array_filter($food);
You can see it here: https://3v4l.org/LjpGD
Reference:
http://php.net/uasort
http://php.net/in_array
http://php.net/array_filter
PS: The code uses the new since PHP 7.0 available spaceship operator. If you don't or can't use PHP7, you have to use an if construct as below for comparison.
if(count($b) > count($a)) {
return 1;
} elseif(count($b) == count($a)) {
return 0;
} else {
return -1;
}

Iterate through multidimensional PHP array and output values

I'm having a real headache trying to iterate through an array and output elements. Using the array structure below I want to be able to output each instance of partname.
The following loop outputs the first instance of partname. I can't seem to adapt it to loop through all instances within the array. I'm sure I'm missing something basic.
foreach($ItemsArray['assignments'] as $item) {
$partname = $item['grades'][0]['partname'];
}
Array
(
[assignments] => Array
(
[0] => Array
(
[assigntmentid] => 5101
[grades] => Array
(
[0] => Array
(
[id] => 5101
[name] => Advanced AutoCad
[partid] => 6601
[partname] => Draft
[userid] => 82069
[grade] => 53
[courseid] => 6265
[fullname] => Computer Aided Design
)
)
)
[1] => Array
(
[assigntmentid] => 5101
[grades] => Array
(
[0] => Array
(
[id] => 5101
[name] => Advanced AutoCad
[partid] => 6602
[partname] => Final
[userid] => 82069
[grade] => 35
[courseid] => 6265
[fullname] => Computer Aided Design
)
)
)
)
)
Instead of just coding by slapping the keyboard. Write down what your function needs to do. In english (or whatever language you prefer). This would be something like:
Foreach assignment, loop over all grades and store the partname of
that grade into an array.
And then code it:
function getPartnames($assignments) {
$partNames = array();
foreach ($assignments as $assignment) {
foreach($assignment['grades'] as $grade) {
$partNames[] = $grade['partname'];
}
}
return $partNames;
}
So what did I do? I simply translated english to code.
Some few more tips: Use variables names that make sense. $item; $ItemArray; ... don't make sense. They tell me nothing
use an extra foreach in your loop:
foreach($ItemsArray['assignments'] as $item) {
foreach($item['grades'] as $grade) {
echo $grade['partname'];
}
}

Name-value and key-value pairs both being created in PHP file (for json encode)

I am generating PHP arrays from a MySQL database, with the output to be converted to JSON using json_encode (ultimately for use with Twitter typeahead).
Based upon everything I've read about PHP arrays, I had expected the select query to generate - for any record - just a single key-value pair for each column.
Instead, I seem to be getting both a name-value pair and a key-value pair.
For instance, for a table with 5 columns, the set of values FOR A SINGLE RECORD are in the form:
[fieldname1] => value1 [0] => value1
[fieldname2] => value2 [1] => value2
[fieldname3]] => value3 [2] => value3
[fieldname4]=> value4 [3] => value4
[fieldname5] => value5 [4] => value5
When I use json_encode it generates the following JSON string for that record - which is twice as long as it needs to be because I am getting both the name-value pair and the key-value pair (so the the value is repeated very line).
"fieldname1":"value1","0":"value1",
"fieldname2":"value2","1":"value2",
"fieldname3":"value3","2":"value3",
"fieldname4":"value4","3":"value4",
"fieldname5":"value5","4":"value5",
What I would prefer is just the 'fieldname1' => 'value1' or its json equivalent.
Here is an example of the code I use in PHP to select the data from the database.
<?php
$sql = "SELECT * FROM `tr_trades_anzsco` WHERE `trade_alias_id` > 898";
$trade = $dbh->query($sql);
foreach($trade as $trade):
$trade_alias_id = $trade['trade_alias_id'];
$trade_alias = trim($trade['trade_alias']);
print_r($trade);
endforeach;
?>
Here is the resultant dataset for just three records.
Array ( [trade_alias_id] => 899 [0] => 899 [trade_alias] => Boilermaker [1] => Boilermaker [ANZSCO_title] => Structural Steel And Welding Trades Workers [2] => Structural Steel And Welding Trades Workers [ANZSCO_code] => 322300 [3] => 322300 [source] => Raj [4] => Raj ) Array ( [trade_alias_id] => 900 [0] => 900 [trade_alias] => Welder [1] => Welder [ANZSCO_title] => Structural Steel And Welding Trades Workers [2] => Structural Steel And Welding Trades Workers [ANZSCO_code] => 322300 [3] => 322300 [source] => Tom [4] => Tom ) Array ( [trade_alias_id] => 901 [0] => 901 [trade_alias] => Rigger [1] => Rigger [ANZSCO_title] => Construction Rigger [2] => Construction Rigger [ANZSCO_code] => 821711 [3] => 821711 [source] => Jack [4] => Jack )
Finally, here is the json string for the final record only (broken up so the structure is more easily visible).
Array ( [0] => Array (
[trade_alias_id] => 901 [0] => 901
[trade_alias] => Rigger [1] => Rigger
[ANZSCO_title] => Construction Rigger [2] => Construction Rigger
[ANZSCO_code] => 821711 [3] => 821711
[source] => Jack [4] => Jack )
)
The duplicate values matter considerably for performance reasons - because the data is to be extracted for use on mobile devices (with Twitter TypeAhead and possibly AngulularJS). Our datasets are already very large ... so twice the json will double the time for fetching the data.
Key question: How I can remove the duplicates either at the PHP stage OR the json_encode stage so as to generate ONLY a name-value pair but not both a name-value and a key-value pair?
Thank you!
Presuming you are using pdo:
$trade = $dbh->query($sql, PDO::FETCH_ASSOC);
You can unset it if the key is int
foreach($trade as $key=>$value) {
if(!is_int($key) {
unset($trade[$key]);
}
}
Hope this helps :D

Efficiently transforming Arrays (PHP)

Edit: Thanks to #Felix Kling and #mario for pointing me towards named capture groups and PREG_SET_ORDER, I totally learned something today.
I'm curious about a better algorithm per se, though. So please just pretend that there's no preg_match() involved.
Edit 2: Abstracted question
While answering another question here, I stumbled upon the fact that my code for turning
this:
Array
(
[0] => Array (
[0] => 1
[1] => 3
)
[1] => Array (
[0] => Description text
[1] => Different Description text
)
[2] => Array (
[0] => 123.456.12
[1] => 234.567.89
)
[3] => Array (
[0] => 10.00
[1] => 10.00
)
[4] => Array (
[0] => 10.00
[1] => 30.00
)
)
into that:
Array
(
[0] => Array
(
[qty] => 1
[description] => "Description text"
[sku] => 123.456.12
[price] => 10.00
[total] => 10.00
)
…
)
is fugly:
$field_names = array('qty', 'description', 'sku', 'price', 'total');
$result_arr = array();
$num_iter = count(matches[0]);
for ($i = 0; $i < $num_iter; $i++) {
foreach ($field_names as $index => $field_name) {
$result_arr[$i][$field_name] = array_shift($input_arr[$index]);
}
}
Any suggestions for improvement?
There is one simpler way to produce the desired output.
while (count($input_arr[0])) {
$values = array_map("array_shift", & $input_arr);
$result_arr[] = array_combine($field_names, $values);
}
This won't work past PHP 5.3, as it requires forcibly passing a parameter by reference. (Avoiding any dumbing-down-the-language remarks here). But you can of course chop off the entries with a more elaborate manual loop at any time.
The real simplification for such cases is however array_combine to turn a list into an associative array.

Categories