Filter an array

I have an array

echo '<pre>';print_r($frontAssetArray);echo '</pre>';

resulting…

Array
(
    [0] => Array
        (
            [name] => 
            [id] => 1
            [beginning_ru] => 42.0
            [ending_ru] => 42.0
            [beginning_x] => 0.0
            [external_width] => 17.500
            [external_depth] => 7.008
            [external_height] => 1.750
            [asset_type] => 3
            [manufacturer] => Hewlett-Packard
            [rack_mounting_direction] => Front
        )

    [1] => Array
        (
            [name] => 
            [id] => 1
            [beginning_ru] => 40.0
            [ending_ru] => 40.0
            [beginning_x] => 0.0
            [external_width] => 17.500
            [external_depth] => 25.591
            [external_height] => 1.750
            [asset_type] => 5
            [manufacturer] => AirTight Networks
            [rack_mounting_direction] => Front
        )

    [2] => Array
        (
            [name] => 
            [id] => 2
            [beginning_ru] => 38.0
            [ending_ru] => 38.0
            [beginning_x] => 0.5
            [external_width] => 17.500
            [external_depth] => 25.591
            [external_height] => 1.750
            [asset_type] => 11
            [manufacturer] => Cleversafe
            [rack_mounting_direction] => Front
        )

    [3] => Array
        (
            [name] => 
            [id] => 1
            [beginning_x] => 0.0
            [beginning_ru] => 36.0
            [ending_ru] => 36.0
            [external_width] => 17.500
            [external_depth] => 28.346
            [external_height] => 1.750
            [asset_type] => 4
            [manufacturer] => IBM
            [rack_mounting_direction] => Front
        )

)

I’m trying to use array_filter() to take all the key/value except 3 (beginning_ru, ending_ru, and external_depth) so it becomes

Array
(
    [0] => Array
        (
            [beginning_ru] => 42.0
            [ending_ru] => 42.0
            [external_depth] => 7.008
        )

    [1] => Array
        (
            [beginning_ru] => 40.0
            [ending_ru] => 40.0
            [external_depth] => 25.591
        )

    [2] => Array
        (

            [beginning_ru] => 38.0
            [ending_ru] => 38.0
            [external_depth] => 25.591
        )

    [3] => Array
        (

            [beginning_ru] => 36.0
            [ending_ru] => 36.0
            [external_depth] => 28.346

        )

)

Define an array of the “KEYs” you want removed.

$remove = array('name','id','beginning_x','external_width','external_height','asset_type','manufacturer','rack_mounting_direction');

If you were to print out this array you would see that those KEYs are the values.

Array
(
    [0] => name
    [1] => id
    [2] => beginning_x
    [3] => external_width
    [4] => external_height
    [5] => asset_type
    [6] => manufacturer
    [7] => rack_mounting_direction
)

As you loop through the array with foreach, array_flip() will place the values as the keys.

Array
(
    [name] => 0
    [id] => 1
    [beginning_x] => 2
    [external_width] => 3
    [external_height] => 4
    [asset_type] => 5
    [manufacturer] => 6
    [rack_mounting_direction] => 7
)

You can then use array_diff_key();, and compare the KEYs of the flipped array to original array, which will return an array of KEYs that are different. This can be assigned to a new array using the main array $k as the new primary key.

$remove = array('name','id','beginning_x','external_width','external_height','asset_type','manufacturer','rack_mounting_direction');
foreach($frontAssetArray as $k => $frontAsset): 
	$newfrontAssetArray[$k] = array_diff_key($frontAsset, array_flip($remove));
endforeach;

Resulting in

Array
(
    [0] => Array
        (
            [beginning_ru] => 42.0
            [ending_ru] => 42.0
            [external_depth] => 7.008
        )

    [1] => Array
        (
            [beginning_ru] => 40.0
            [ending_ru] => 40.0
            [external_depth] => 25.591
        )

    [2] => Array
        (
            [beginning_ru] => 38.0
            [ending_ru] => 38.0
            [external_depth] => 25.591
        )

    [3] => Array
        (
            [beginning_ru] => 36.0
            [ending_ru] => 36.0
            [external_depth] => 28.346
        )

)
1 Like

Assuming this is from a database query, just SELECT the columns that you want. If it is not from a query, supply some context as to where the data is coming from.

We’ve asked that many times in his posts. These arrays are always changing and seem to come from somewhere other than a database. I suspect a teacher.

1 Like

the data will be coming from a mysql database,I do have an array with the info I need allready, I can query the database to get a new array of just the info I need, but would like to know whats the best way to go about this. and if doing the stuff to the existing array is optimal.
Thanks

If I need 3 apples, which of the following is better?

  1. I ask for 10 apples and then throw 7 in the trash
  2. I ask for 3 apples
1 Like

It would be best to select the DB fields you need when making the query.
If you have an array with all fields this array can be used in many ways.
You can display “3 Apples” and have a link to show details, which would then show “10 Apples” but if you don’t need “10 Apples” why query for them.

ok, ill create a new array with just what I need. I always thought you should never query the database more than needed.

Well like I said, ONE query could be used many ways on a page. Only display certain items like the ones mentioned in this thread in one area and loop through the array in another area to display other values… No need to query twice or more if the information can be found on one array.

I guess the point or question is, why do you need to change the array to use it?

the reason is I use the array (frontAssets) to display this


So, when displaying the front,(external_width) is needed
But in the side view, I’d use external_depth in its place. your right though, I need to modify the query to work with both views.

Most impressed with your display sir.
The full array can be used to loop through that dimensions section. Just use the field/keys you need.

1 Like

ok, thanks…
I made the change and was able to use the existing array and used the three keys I needed. Heres what I have


What im looking at is the table

<table class="table table-striped table-sm">
<thead>
<tr>
<th>Slot</th><th>Depths</th>
</tr>
</thead>								  
<tbody> 		
<tr><td>42</td><td>7.008</td></tr>
<tr><td>36</td><td>28.346</td></tr>
<tr><td>40</td><td>25.591</td></tr>
<tr><td>42</td><td>18.740</td></tr>
<tr><td>Array
(
    [0] => 38
    [1] => 39
    [2] => 40
)
</td><td>20.000</td></tr>
<tr><td>38</td><td>25.591</td></tr>								  
</tbody>
</table> 

Using

<table class="table table-striped table-sm">
<thead>
<tr>
<th>Slot</th><th>Depths</th>
</tr>
</thead>								  
<tbody> 		
<?php

//echo '<pre>';print_r($assetArray);echo '</pre>';
  
 	foreach($assetArray as $asset) {

	  echo "\r\n";
	  echo '<tr><td>';
		if($asset['ending_ru'] - $asset['beginning_ru'] == 0) { echo (float)$asset['ending_ru']; } else { $RUs = range((float)$asset['beginning_ru'],(float)$asset['ending_ru']); print_r($RUs); } 
	  echo '</td><td>';
	  echo $asset['external_depth']; 
	  echo '</td></tr>';
	}		

?>							  
</tbody>
</table> 

Im trying to get the table arranged in a way like

<table class="table table-striped table-sm">
<thead>
<tr>
<th>Slot</th><th>Depths</th>
</tr>
</thead>								  
<tbody> 		
<tr><td>42</td><td>7.008 + 18.740</td></tr>
<tr><td>36</td><td>28.346</td></tr>
<tr><td>40</td><td>25.591 + 20</td></tr>
<tr><td>39<td>20.000</td></tr>
<tr><td>38</td><td>25.591 + 20</td></tr>								  
</tbody>
</table> 

so that every slot has a depth and that if a slot has 2 (front and back) depths, they could be added together.

Somebody once said something about the waste of time applying premature optimisation.

There is always a better way to create the desired output so I would just get it to work first by removing the following line and replacing with a function:

// complicated line to replace:
if($asset['ending_ru'] - $asset['beginning_ru'] == 0) { echo (float)$asset['ending_ru']; } else { $RUs = range((float)$asset['beginning_ru'],(float)$asset['ending_ru']); print_r($RUs); } 

// replacement:
echo getRow($asset);

/// ...

//==============================================
/* 
  usage:
  echo getRow($asset);
*/  
//==============================================
function getRow( array $asset=[])
: string 
{ 
  $result = '>>> PROBLEM <<<';

  // DEBUG:
  // echo '<pre>'; print_r($asset); echo '</pre>'; 
  // die;

  $ok = (int) $asset['ending_ru'] - (int) $asset['beginning_ru'] == 0;
  if($ok) {
    // $echo (float) $asset['ending_ru']; 
    $result = (float) $asset['ending_ru']; 
  } else { 
    $RUs = range((float)$asset['beginning_ru'],(float)$asset['ending_ru']); 
    // print_r($RUs); 
    $result = $RUs;
  } 

  return $result;  
}//


/

When you say, “they could be added together.” Are they displayed like above or added together, i.e. 45.591.

If you want the front and back depths adding together for each slot then I would take our ONE query result array and build one that fits the needs of this display placing the slot as the primary KEY.

$AllassetArray[(float)$asset['ending_ru']]

Now you can add numbers together in a loop by using += but you need to have a value first so I will make an IF condition saying IF NOT ISSET, SET this ARRAY[KEY] = 0;

if(!isset($AllassetArray[(float)$asset['ending_ru']])){$AllassetArray[(float)$asset['ending_ru']] = 0;}

Then any depths that have this slot will be added to this and accumulate as the loop continues.

$AllassetArray[(float)$asset['ending_ru']] += $asset['external_depth'];

After the loop has built this new array you may find the slots are not in an order you like so you can use ksort() or krsort() to get things in the display order you like. Using

krsort($AllassetArray);

will give you this.

Array
(
    [42] => 25.748
    [40] => 45.591
    [38] => 45.591
    [36] => 28.346
)

Remember you can make one query and sort it many different ways to be used on different sections of your web page and it can and should be done before anything is sent to the browser.

$AllassetArray = array();
foreach($assetArray as $k => $asset):
	if(!isset($AllassetArray[(float)$asset['ending_ru']])){$AllassetArray[(float)$asset['ending_ru']] = 0;}
	$AllassetArray[(float)$asset['ending_ru']] += $asset['external_depth'];	
endforeach;
krsort($AllassetArray);

Then when it comes to making your display it becomes very straight forward and clean without a bunch of php within html.

<table class="table table-striped table-sm">

	<thead>
		<tr>
			<th>Slot</th>
			<th>Depths</th>
		</tr>
	</thead>
	
	<tbody>
	<?php
	foreach($AllassetArray as $slot => $depth):
		echo '<tr>
			<td>'.$slot.'</td>
			<td>'.$depth.'</td>
		</tr>'."\r";
	endforeach;
	?>	
	</tbody>
</table>

Like so.

I guess this answers my own question from post #9 as to why you might want to change your array. I guess there’s a right time for everything.

1 Like

As an alternative, you could let MySQL solve this

SELECT ending_ru AS slot, SUM(external_depth) AS depth FROM daTable GROUP BY ending_ru;
1 Like

So, it turns out that the actual top level goal is to preprocess the data to expand any range and add the external_depth at each ru position?

$result = [];
foreach($assetArray as $asset)
{
	// test for an ru range
	if($asset['ending_ru'] == $asset['beginning_ru'])
	{
		// a single ru position
		// create entry if it doesn't exist
		if(!isset($result[(float)$asset['ending_ru']]))
		{
			$result[(float)$asset['ending_ru']] = 0.0;
		}
		// add ext depth
		$result[(float)$asset['ending_ru']] += $asset['external_depth'];
	} else {
		// a range of ru positions
		foreach(range((float)$asset['beginning_ru'],(float)$asset['ending_ru']) as $ru)
		{
			// create entry if it doesn't exist
			if(!isset($result[$ru]))
			{
				$result[$ru] = 0.0;
			}
			// add ext depth
			$result[$ru] += $asset['external_depth'];
		}
	}
}

echo '<pre>';print_r($result);echo '</pre>';

Result -

Array
(
    [42] => 25.748
    [40] => 45.591
    [38] => 45.591
    [36] => 28.346
    [39] => 20
)

Edit: or more simply treat a single entry as a range of one -

$result = [];
foreach($assetArray as $asset)
{
	foreach(range((float)$asset['beginning_ru'],(float)$asset['ending_ru']) as $ru)
	{
		// create entry if it doesn't exist
		if(!isset($result[$ru]))
		{
			$result[$ru] = 0.0;
		}
		// add ext depth
		$result[$ru] += $asset['external_depth'];
	}
}
1 Like

ok, heres the result of

echo '<pre>';print_r($assetArray);echo '</pre>';
echo '<pre>';print_r($AllassetArray);echo '</pre>';

its my array, with the modified array which has only the stuff needed


Array
(
    [0] => Array
        (
            [name] => 
            [id] => 1
            [beginning_ru] => 39.0
            [ending_ru] => 39.0
            [beginning_x] => 0.5
            [external_width] => 17.500
            [external_depth] => 1.969
            [external_height] => 1.750
            [asset_type] => 8
            [manufacturer] => CAT6Plus
            [rack_mounting_direction] => Front
        )

    [1] => Array
        (
            [name] => 
            [id] => 1
            [beginning_ru] => 42.0
            [ending_ru] => 42.0
            [beginning_x] => 0.0
            [external_width] => 17.500
            [external_depth] => 22.500
            [external_height] => 1.750
            [asset_type] => 5
            [manufacturer] => Cisco
            [rack_mounting_direction] => Front
        )

    [2] => Array
        (
            [name] => 
            [id] => 1
            [beginning_ru] => 40.0
            [ending_ru] => 42.0
            [beginning_x] => 0.0
            [external_width] => 9.764
            [external_depth] => 11.417
            [external_height] => 4.882
            [asset_type] => 11
            [manufacturer] => Dell
            [rack_mounting_direction] => Back
        )

)

Array
(
    [42] => 33.917
    [39] => 1.969
)

I like how the modified array is simple and has only what I need (the key is the row number and the value is the depths which are in that row.
I added three assets to a rack like

But the result seems to show only the two

using

	foreach($AllassetArray as $slot => $depth):
	  echo '<tr>';
	  echo '<td>'.$slot.'</td>';
		if($row['internal_rail_depth'] < $depth) {
			echo '<td>'.$depth.'</td><td><span class="text-danger icon-remove"></span></td>';
		} else {
			echo '<td>'.$depth.'</td><td><span class="text-success icon-ok"></span></td>';
		}
	  echo '</tr>'."\r";
	endforeach;

@lurtnowski, while your post above is listed as being a reply to my post, the code you are using is not what I wrote for this. If it was, you would be getting the following result, which expands the 40-42 range entry -

Array
(
    [39] => 1.969
    [42] => 33.917
    [40] => 11.417
    [41] => 11.417
)

Yes, Mabismad’s coding takes into account the range of slots being used by larger components.

[off-topic]
I would like to be able to test the solutions locally and having trouble with PHP syntax.

Can anyone supply PHP sample script to produce the rendered array in the original post?
[/off-topic]