Group matched array values - php

Program:
while($i<=$row) {
echo $arr[$i][1].$arr[$i][4]
}
Output
Product Code Qty
KC_DRINK_TASTY_CASE 1
KC_DRINK_TASTY_CASE 1
KC_DRINK_TASTY_CASE 1
KC_DRINK_TASTY_CASE 1
KC_SUNGLASSES_BK 1
KC_SUNGLASSES_BK 1
KC_SUNGLASSES_BE 1
KC_SUNGLASSES_BE 1
KC_SUNGLASSES_OE 1
KC_SUNGLASSES_OE 1
KC_SUNGLASSES_RD 1
KC_SUNGLASSES_RD 1
KC_SUNGLASSES_WE 1
KC_SUNGLASSES_WE 1
I want it to output
KC_DRINK_TASTY_CASE 4
KC_SUNGLASSES 10
so that it group product code excluding last underscore and sum their quantity

If $arr looks something like this:
$arr = array(
array('{something}', 'KC_DRINK_TASTY_CASE', '{something}', '{something}', 1),
array('{something}', 'KC_SUNGLASSES_BK', '{something}', '{something}', 1),
// ...
);
Then you can get the output what you what like this:
// we'll store counts here
$result = array();
foreach ($arr as $row) {
$product = $row[1];
$qty = $row[4];
// figure out where the last underscore is and chop off everything that follows it
// this is VERY brittle. If the product ends up with a name like _SOMEKEY you'll end
// up with an empty key. Not good. Probably not a huge issue, but buyer beware
$_product = substr($product, 0, strrpos($product, '_'));
if (isset($result[$_product])) {
$result[$_product] += $qty; // we already started counting
} else {
$result[$_product] = $qty; // not started counting this product yet, start it
}
}
// now print your result:
foreach ($result as $id => $qty) {
echo $id, "\t", $qty, PHP_EOL;
}

Related

PHP-Data txt - Two-dimensional Array - Data grouping per record

I need to read, line aligns and group by (Cd), which is the only index of each record. Thus, (Cd) refers to each new record, which may contain several sub groups: (11), (22), (Co), etc. These sub groups may contain an additional line (see example of (Co) in the first record, which should concatenate the lines containing "for cabinet" and "for closet.").
My TXT file structure, is this:inventory.txt
>No. 0012 of 01/31/2016
>No. 0012 of 01/31/2016
>(Cd) 12345
>(11) Cod1-023
>(22) 22/12/1945
>(Co) locking doors
>For cabinet
>For closet.
>(Cd) 23456
>(11) Cod1-055
>(21) 01/01/2005
>(22) drawer iron
>,wood
>,aluminum
>(Cd) 78920
>(22) Cod1-077
>(54) 2/22/1975
>(Co) clip Aluminum or iron
>(74) anodized
>(Cd) 0002525
>(Di) Cod4-07100
>(11) 02/22/2017
>(22) shirt Red green
>(54) yellow buttons
>(Co) mango
>,avocado
>,cherry
I implemented the following routine but, after much research and modifications, I was not able to group the sub indices:
Together, I need a routine to transfer the data from the array to variables and, later, to the mysql DB.
If anyone can give me a light, thank you.
$cd = [];
$group = [];
$counter = 0;
$file = fopen ('inventory.txt', 'r');
while (! feof ($file)) {
$row = trim (fgets ($file, 1024));
// $row = trim ($row);
if (substr ($row, 0, 4) == '(cd)') {
$counter = 0;
if (! empty ($group)) {
$cd [$id] = $group;
$group = [];
$counter = 0;
}
$id = substr ($row, 5, strlen ($row) -5);
$cd [$id] [] = $line;
} else {
if (substr ($row, 0, 4)! == '(11)') {
if (isset ($group [$counter-1])) {
$group [$counter -1]. = ''. $line;
$counter--;
}
} else {
$group [] = $row;
}
$counter ++;
}
}
$cd [$id] = $group;
fclose ($file);
echo '<pre>';
print_r ($cd);
exit;
// -------------------------
// routine to transfer data from array to variables
$keys = array_keys ($cd);
for ($i = 0; $i <count ($cd); $i ++) {
echo $keys [$i]. "<br>";
foreach ($cd [$keys [$i]] as $key => $value) {
echo $key. ":". $value. "<br>";
}
echo "<br>";
}
Thank you for editing your question to attach the file content rows. Here is my new solution.
This will disallow concatenation for any lines immediately after a (22) line.
If there are other triggers beyond (22) that should indicate concatenation is unwanted, modify the $concat condition in the second elseif block.
$cd=[]; // declare array
$i=-1; // set outer index
$concat=true;
$file=fopen('inventory.txt','r');
while(!feof($file)){
$row=trim(fgets($file,1024));
if(preg_match('/^\(Cd\)\s(.+)/',$row,$match)){ // capture Cd numbers
++$i; // increment outer_index
$j=-1; // reset inner_index
$id=$match[1]; // store cd value
$concat=true;
}elseif(preg_match('/^(\(..\)\s.*)/',$row,$match)){ // capture Cd data
++$j; // this is a new innerarray element, increment its index
$cd[$i][$id][$j]=$match[1]; // push element into array
$concat=(strpos($match[1],'(22)')!==0?true:false);
}elseif(isset($id) && $concat){ // ignore all file header content
$cd[$i][$id][$j].=" $row"; // concatenate to last element
}
}
echo "<pre>";
var_export($cd); // display in true nested form
echo "</pre>";
foreach($cd as $outer_index=>$cdarrays){
foreach($cdarrays as $id=>$innerarrays){
foreach($innerarrays as $inner_index=>$line){
echo "$outer_index : $id : $inner_index = $line<br>"; // display keys & values by row
}
}
}
The $cd array will have this structure:
array (
0 =>
array (
12345 =>
array (
0 => '(11) Cod1-023',
1 => '(22) 22/12/1945',
2 => '(Co) locking doors For cabinet For closet. ',
),
),
1 =>
array (
23456 =>
array (
0 => '(11) Cod1-055',
1 => '(21) 01/01/2005',
2 => '(22) drawer iron',
),
),
2 =>
array (
78920 =>
array (
0 => '(22) Cod1-077',
1 => '(54) 2/22/1975',
2 => '(Co) clip Aluminum or iron',
3 => '(74) anodized',
),
),
3 =>
array (
'0002525' =>
array (
0 => '(Di) Cod4-07100',
1 => '(11) 02/22/2017',
2 => '(22) shirt Red green',
3 => '(54) yellow buttons',
4 => '(Co) mango ,avocado ,cherry',
),
),
)
Or if you want to view it in a flattened/verbose style:
0 : 12345 : 0 = (11) Cod1-023
0 : 12345 : 1 = (22) 22/12/1945
0 : 12345 : 2 = (Co) locking doors For cabinet For closet.
1 : 23456 : 0 = (11) Cod1-055
1 : 23456 : 1 = (21) 01/01/2005
1 : 23456 : 2 = (22) drawer iron
2 : 78920 : 0 = (22) Cod1-077
2 : 78920 : 1 = (54) 2/22/1975
2 : 78920 : 2 = (Co) clip Aluminum or iron
2 : 78920 : 3 = (74) anodized
3 : 0002525 : 0 = (Di) Cod4-07100
3 : 0002525 : 1 = (11) 02/22/2017
3 : 0002525 : 2 = (22) shirt Red green
3 : 0002525 : 3 = (54) yellow buttons
3 : 0002525 : 4 = (Co) mango ,avocado ,cherry
#mickmackusa I have much to thank for your patience and contribution. His code was excellent, but he was eliminating the lines he was leaping (22). So, I modified the structure to capture the values of those following, including in a new ID inside the array.
My array knowledge is very limited, but the code is functional for my needs.
In case you can contribute to simplify the operation that I built, I'm happy to know.
Why error Occurs "Warning: Undefined offset: 3 and Undefined offset: 5, in this line: $cd[$i][$id][$j]. = "$Row";
$cd=[]; // declare array
$trash=[];
$i=-1; // set outer index
$concat=true;
$file=fopen('inventory.txt','r');
while(!feof($file)){
$row=trim(fgets($file,1024));
if(preg_match('/^\(Cd\)\s(.+)/',$row,$match)){ // capture Cd numbers
++$i; // increment outer_index
$j=-1; // reset inner_index
$id=$match[1]; // store cd value
$concat=true;
$row_previous=false;
$row_ob=false;
}elseif(preg_match('/^(\(..\)\s.*)/',$row,$match)){ // capture Cd data
++$j; // this is a new innerarray element, increment its index
$cd[$i][$id][$j]=$match[1]; // push element into array
//$concat=(strpos($match[1],'(Co)')!==0?true:false);
If (substr($row, 0, 5) == '(Co) ') {
$row_previous=true;
}
}elseif(isset($id)){ // ignore all file header content
If (($row_previous == true)and ($row_ob !== true)){
++$j; //increment its index to insert variable value created for the additional lines
$row="(Ob) ". (trim($row)); //create pre value variable
$row_ob=true;
$cd[$i][$id][$j].="$row "; // concatenate to last element to new
}else{
$cd[$i][$id][$j].=" $row"; // concatenate to last element
}
}
}
echo "<pre>";
var_export($cd); // display in true nested form
echo "</pre>";
foreach($cd as $outer_index=>$cdarrays){
foreach($cdarrays as $id=>$innerarrays){
foreach($innerarrays as $inner_index=>$line){
echo "$outer_index : $id : $inner_index = $line<br>"; // display keys & values by row
}
}
}

Combine 2 while loop results

We have 2 while loops , we are displaying 2 different results with both.
we need to combine or without combining we need to merge 2 results.
in below image ,
1st while loop result = > 1st, 2nd, 6th rows.
2nd while loop result = > 3rd, 4th, 5th rows.
we need 3rd , 4th & 5th rows results in 1st, 2nd 6th rows in last 2 columns [ Paid status & commission ].
1st while results coming from Database 1 & 2nd while results are coming from Database 2 with table [order_details]
$stmt = $user_home->runQuery("SELECT * FROM order_details");
$stmt->execute(array(":uid" => $_SESSION['userSession']));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$stmt->execute();
$i = 0;
foreach($order as $orderData)
{
$k = 0;
$orderitems = $orderData['dproduct_id'];
$orderitemsarray = explode(",", $orderitems);
/* 1st while */
while ($k < count($orderitemsarray))
{
if ($orderitemsarray[$k] != '0')
{
$stmtorders = $user_home->runQuery("SELECT * FROM order_details");
$stmtorders->execute(array(":dorder_id" => $orderData['entity_id']));
$roworders = $stmtorders->fetch(PDO::FETCH_ASSOC);
$dorderStatus = $roworders['dpaid_status'];
$productdetail = Mage::getModel('catalog/product')->load($orderitemsarray[$k]);
$designer_id = $productdetail->getDesignerID() ;
if($accountType == "admin")
{
$designerName = getDesignerName($productdetail->getDesignerID()) . " -(" . $productdetail->getDesignerID() . ")";
$responce[] = array(
$orderData->getIncrementId() ,
$orderitemsarray[$k],
$productdetail->getName() ,
$designerName,
$orderData['status'],
$data['dpaid_status'],
$data['commission'],
$sDate
);
}
}
$k++;
$i++;
}
/* 2nd while */
while($data = $stmt->fetch())
{
$responce[] = array(
$data['dorder_id'],
$data['dpaid_status'],
$data['commission']
);
$k++;
}
}
I tried below code , but it results as below image - means only 2 rows displayed instead of 23 rows....
while (($k < count($orderitemsarray)) && ($data = $stmt->fetch()))
Full page looks as below :
I am new to php world & tried lot before posting here....
The thing is whenever you use empty brackets [] an index is automatically assigned which is equal to the next available numeric value and your data ends up in a next position so correct index is equired to solve this issue .
In while (($k < count($orderitemsarray)) && ($data = $stmt->fetch()))
If either of condition fails then loop ends and your $data probably has only three entries it's showing only that many even though $orderitemsarray has many more , i am not sure but you can prolly replace while with if statement and change index like this to make those stuff append on same row
$indx=0;
foreach($order as $orderData)
{
$k = 0;
//.. Stufff
/* 2nd while */
if($indx == 0 || $indx == 1 || $indx == 5)
{
if($data = $stmt->fetch())
{
$size = count($responce); // get size from that get its last index
$responce[$size-1] = array(
$data['dorder_id'],
$data['dpaid_status'],
$data['commission']
);
$k++; //<-- not sure why it's here but doesn't matter may be some magento stuff?
}
}
$indx++
}
EDIT:sry my bad , ignore my last comment try this instead
$responce[$size-1] = array_merge($responce[$size-1] , array(
$data['dorder_id'],
$data['dpaid_status'],
$data['commission']
) );

Finding out combinations of x amount of integers to sum a given number

I am trying to figure out how I can loop out possible combinations of a x amount of integers to sum a specifik number.
Let's say, I have number 7 and I need to figure out how I can sum that number with integers in pairs 3.
1+2+4 = 7
3+3+1 = 7
5+1+1 = 7
2+2+3 = 7
Repeated combinations of numbers doesn't interest me, e.g.:
1+2+4 = 7
2+4+1 = 7
4+2+1 = 7
Anyone got any ideas of how I should proceed to reach this result?
Thanks.
Here is the solution for your problem.
function printPartitions($target, $max, $s){
if($target === 0 )
echo $s;
else
{
if($max > 1)
{
printPartitions($target, $max-1, $s);
}
if($max <= $target)
{
printPartitions($target-$max, $max, $max . " " . $s);
}
}
}
printPartitions(5, 5, "<br/>");
You have to specify the $target Value, $max value.
e.g.
printPartitions(7, 7, "<br/>");
It will give you output like:
1 1 1 1 1 1 1
1 1 1 1 1 2
1 1 1 2 2
1 2 2 2
1 1 1 1 3
1 1 2 3
2 2 3
1 3 3
1 1 1 4
1 2 4
3 4
1 1 5
2 5
1 6
7
I've got a solution to my problem. I feel I should defientely share it here, if anyone would ever need it. My solutions is based on this post: https://stackoverflow.com/a/19067884/3293843
<?php
function sampling($chars, $size, $combinations = array()) {
# if it's the first iteration, the first set
# of combinations is the same as the set of characters
if (empty($combinations)) {
$combinations = $chars;
}
# we're done if we're at size 1
if ($size == 1) {
return $combinations;
}
# initialise array to put new values in
$new_combinations = array();
# loop through existing combinations and character set to create strings
foreach ($combinations as $combination) {
foreach ($chars as $char) {
$new_combinations[] = $combination .'#'. $char;
}
}
# call same function again for the next iteration
return sampling($chars, $size - 1, $new_combinations);
}
// example
$chars = array('1', '2', '3','4');
$target = 7;
$maxLengthOfIntegers = 3;
$output = sampling($chars, $maxLengthOfIntegers);
$repeatedEntries = array();
//presenting the output
foreach($output as $out){
$explodeOut = explode('#',$out);
sort($explodeOut);
if(array_sum($explodeOut) == $target){
$sortedPattern = implode('',$explodeOut);
if(!in_array($sortedPattern,$repeatedEntries)){
echo $sortedPattern.'<br/>';
$repeatedEntries[] = $sortedPattern;
}
}
}
?>
Thank you for your time and efforts.
Regards,
Jacob
you can try this algorithm
$ans = array();
for($i=1;$i<=5;$i++)
{
$i1 = 7-$i;
$i2 = intval($i1 - $i);
$value = $i."+".$i1."+".$i2;
$ans = array_unshift($ans,$value);
}
print_r($ans);
hope this helps.. PLease let me know

Array from Arrays

I have the following array:
$learners=array('Eliza'=87, 'Joe'=81, 'Anne'=69, 'Marley'=39, 'Teddy'=39, 'Jemma'=90, 'Sylvia'=87);
So far I have been able to separate the two arrays as follows:
$tudents=array_keys($learners);
$scores=array_values($learners);
The ranking is as follows:
Student Score Position
Jemma 90 1
Sylvia 87 2
Eliza 87 2
Joe 81 4
Anne 69 5
Marley 39 7
Teddy 69 7
I would like to create a new array with names as keys and positions as values i.e
$positions=array('Jemma'=1, 'Sylvia'=2, 'Eliza'=2, 'Joe'=4, 'Anne'=5, 'Marley'=7, 'Teddy'=7);
This will allow me to echo any name and position at any point on the script. I am not sure how to proceed.
The ranking is not straightforward if the scores have duplicates. If there is a tie at number 2, the 3rd position is skipped. If the tie occurs at the end of the scores, then both scores will be placed at the last position and the preceding position will be skipped, in the example above, position 6 has been skipped and the two 39s occupy position 7.
Any help will be appreciated
// Sort decending
arsort($data);
$vals = array_values($data);
$last = end($vals); // The lowest score
$prev = null;
$rank = 0;
$positions = array();
foreach($data as $student => $score) {
if ($score == $last) {
// The score is the same as the lowest, the rank is set to last position
$rank = count($data);
} else if ($prev != $score) {
// We only update if the score is not the same as prev
$rank++;
} else if ($prev == $score) {
// We matched on the key, replace any items with the
// same score with the current rank
$matches = array_keys($positions, $score);
foreach($matches as $key) {
$positions[$key] = $rank;
}
$positions[$student] = $rank;
// Now skip ahead to the next rank +1
$rank = $rank + count($matches) + 1;
continue;
}
$positions[$student] = $rank;
$prev = $score; // Remember the previous score
}
var_dump($positions);
Here's another solution:
First sort by value (the print_r is just to check progress).
arsort($learners);
print_r($learners);
Then make an array of rankings, but don't advance the rank if the score is the same as the previous element's score.
$rank = $pos = 1;
$prev_score = current($learners);
foreach ($learners as $name => $score) {
if ($score != $prev_score) {
$rank = $pos;
}
$ranking[$name] = $rank;
$prev_score = $score;
$pos++;
}
print_r($ranking);
Now correct the last entries, any element with the same score as the last element should be in 7th place. There's a rarely-used argument to array_keys() that searches for a given value.
$low_score = end($learners);
$last_place = count($learners);
foreach (array_keys($learners, $low_score) as $name) {
$ranking[$name] = $last_place;
}
print_r($ranking);
Output:
Array
(
[Jemma] => 90
[Sylvia] => 87
[Eliza] => 87
[Joe] => 81
[Anne] => 69
[Marley] => 39
[Teddy] => 39
)
Array
(
[Jemma] => 1
[Sylvia] => 2
[Eliza] => 2
[Joe] => 4
[Anne] => 5
[Marley] => 6
[Teddy] => 6
)
Array
(
[Jemma] => 1
[Sylvia] => 2
[Eliza] => 2
[Joe] => 4
[Anne] => 5
[Marley] => 7
[Teddy] => 7
)
Looks like PHP, right?
Basically go through your initial list and stuff them into a new array that uses the names as keys (you're in trouble here if two people have the same name, but I'm assuming this is a homework assignment and that's not an issue?)
$sorted = array();
for ($i=0;$i<count($positions);$i++) {
if (!isset($sorted[$positions[$i]["Student"]])) {
$sorted[$positions[$i]["Student"]] = $positions[$i]["Score"];
} else if ($sorted[$positions[$i]["Student"]]<$positions[$i]["Score"] {
$sorted[$positions[$i]["Student"]] = $positions[$i]["Score"];
}
}
What you're doing here is making an array where the KEY is the name of the student, and putting the first score you find in as the VALUE for that. So $sorted["Jemma"] = 90. Then if you hit that name again, and the score is higher than the current value for $sorted["Jemma"], you're replacing it.
After that, you run an arsort($sorted) to put it in order.

Double Foreach unexpected result

I have two arrays, both associative;
ArrayUneaten ( lemon=> 7, banana=>6, apple=>10)//the units of UNeaten fruit
ArrayOrdered (lemon =>10, strawberry =>10, Kiwi=>0, Apple=>20, Banana=>6) // the units of ordered fruit
I want to create a third array (numeric is fine if in the same order as ArrayOrdered)
of all fruit options and the % of Fruit Eaten (compared to Fruit Ordered).
(NB for other reasons if Ordered Value = 0, %eaten = 0%)
(NB2, note that % desired for strawberries is 100, no strawberries are uneaten, 10 ordered, therefore 10 have been eaten)
So desired Array
ArrayEatenPercentage (70, 100, 0, 50, 0)
My coding attempt
$CompletedPercentagesArray = array ();
foreach( $ArrayOrdered as $fruitOrdered => $unitsOrdered) {
if ($unitsOrdered == 0){
//if it's zero it's never been selected
$completedPercentage = 0;
}
foreach( $ArrayUneaten as $fruitUneaten => $unitsUneaten) {
if ( $fruitUneaten == $fruitOrdered){
// ($totalCardsChosen = $timesSelected*25; - please ignore)
$percentageUneaten = 100*($fruitUneaten/$unitsOrdered);
$percentageEaten = 100 - $percentageUneaten;
$completedPercentage = round ($percentageEaten, 1);
}
else {//if this is true then it's been selected and been finished
$completedPercentage = 100;
}
}
array_push( $completedPercentagesArray, $completedPercentage ); //this adds the variable to the array
}
print_r($completedPercentagesArray);
Current output is unexpected.
Only last value of ArrayUneaten is processed correctly.
The other values return 100%.
ArrayEatenPercentage (100, 100, 100, 50, 100)
Assuming all fruits are in the "ordered" array, you could try something like this:
$results = array();
foreach( $arrayOrdered as $fruit => $numOrdered ) {
if( Isset( $arrayUneaten[$fruit] ) ) {
$numEaten = $numOrdered - $arrayUneaten[$fruit];
} else {
$numEaten = $numOrdered;
}
if( $numOrdered > 0 ) {
$percentEaten = $numEaten / $numOrdered * 100;
} else {
$percentEaten = 0;
}
$results[$fruit] = array( 'eaten' => $numEaten, 'percent' => $percentEaten );
}
Your result array would be keyed on fruit and have both the absolute amount eaten and the percentage.
You should have added break; at the end of if ( $fruitUneaten == $fruitOrdered){ condition block. Otherwise unless the current fruit is the last element(which is apple) of $ArrayUneaten, $completedPercentage becomes always 100, because on the last iteration of the inner loop exection goes to that else block.

Categories