0

I am parsing a JSON file and I have filtered out the values I wanted based on a certain key then loop through it to create variables for the other key values I want. Now that I have it sorted I am not sure how to order it so it displays in the order I want. Is there a simplified way to filter and order in one quick function or do I need to order it separately and if so what would be the best approach?

Here is a snippet from the code for filtering the array based on the "event" key before the loop. Also the order below is the order in which I want them displayed when output too.

$str = file_get_contents($url); // put the contents of the file into a variable
$o=json_decode($str,true);
$features=$o['features'];

// Lets filter the response to get only the values we want
$filtered = array_filter($features,function($el){
    $alerts = array('Tornado Warning', 'Severe Thunderstorm Warning', 'Hurricane Warning', 'Tropical Storm Warning', 'Flash Flood Warning', 'Flood Warning', 'Tornado Watch', 'Severe Thunderstorm Watch', 'Hurricane Watch', 'Tropical Storm Watch', 'Flash Flood Watch');

    return in_array($el['properties']['event'],$alerts);
});
3
  • 1
    Sorting and filtering 2 different routines. It is always best practice to have single responsibility for each routine. Code Review: you don't need to declare array in callback function. Yet you can declare array before array_filter and then pass array variable using "use" keyword Commented Aug 20, 2017 at 4:26
  • There IS a better way to do this, and I don't see it in Manuel's answer. Please provide some sample data. What is $features and what is your expected output? Commented Aug 20, 2017 at 5:24
  • Including sample data ($features) gives your question context and allows readers to verify for themselves if the accepted answer does, in fact, work as well as helps them to understand how the process works. Even though you have received your answer, your question should still be improved/edited to include this vital component of a good question. We don't know if there may be duplicate values in $features nor how it should be handled/sorted when there is a tie/duplicate $alert value in event. SO pages help countless readers in the future (or at least they should). Commented Aug 22, 2017 at 1:34

3 Answers 3

3

Use array_filter(), array_flip(), and usort():

$alerts = array(
    'Tornado Warning', 
    'Severe Thunderstorm Warning', 
    'Hurricane Warning', 
    'Tropical Storm Warning', 
    'Flash Flood Warning', 
    'Flood Warning', 
    'Tornado Watch', 
    'Severe Thunderstorm Watch', 
    'Hurricane Watch', 
    'Tropical Storm Watch', 
    'Flash Flood Watch',
);

// filter features, remove those which are not of any of the desired event types 
$alertFeatures = array_filter($features, function(array $feature) use ($alerts) {
    $eventType = $feature['properties']['event'];

    return in_array($eventType, $alerts);
});

// flip alerts, mapping names of alerts to index in array (we'll use it to order)
$order = array_flip($alerts);

// sort elements by order of event type as desired
usort($alertFeatures, function (array $a, array $b) use ($order) {
    $eventTypeA = $a['properties']['event'];
    $eventTypeB = $b['properties']['event'];

    return $order[$eventTypeA] - $order[$eventTypeB];
});

var_dump($alertFeatures);

For reference, see:

Sign up to request clarification or add additional context in comments.

1 Comment

neat, didn't think of that.
0

Probably not the most efficient solution, but you could make a nested iteration over the array and copy out the relevant features in the right order.

function filterAndSort($features, $alerts){
    $output = array();

    $features_count = count($features);
    $alerts_count = count($alerts);

    for($i=0;$i<$alerts_count;$i++){
        for($u=0;$u<$features_count;$u++){
            if($alerts[$i]==$features[$u]['properties']['event'])
                $output[] = $features[$u];
        }
    }

    return $output;
}

EDIT: The only other way I could think of would be to create a temporary array for each type and then join all those arrays together. But I doubt that will have any significant performance gains. It'll definitely cost more RAM.

function filterAndSort($features, $alerts){
    $output = array();
    $groups = array();

    $features_count = count($features);
    $alerts_count = count($alerts);

    for($i=0;$i<$alerts_count;$i++){ // create empty arrays for each alert type
        $groups[$i] = array();
    }

    for($u=0;$u<$features_count;$u++){
        $index = array_search($features[$u]['properties']['event'],$alerts); // get index of alert type
        if($index!==false) // if feature has one of the relevant alert types
            $groups[$index][] = $features[$u]; // push the the feature into the designated array
    }

    for($i=0;$i<$alerts_count;$i++){
        $group_count = count($groups[$i]);
        for($u=0;$u<$group_count;$u++){
            $output[] = $groups[$i][$u]; // copy each element into the output in the right order
        }
    }

    return $output;
}

Comments

0

You can simply recreate array like this:

function selectByKey($keys,$array){
  $prepare = array();
  foreach($keys as $key){
    $prepare[$key] = $array[$key];
  }
  return $prepare;
}

And use it like this:

$all_items = array(
  'item1' => 'Item 1',
  'item2' => 'Item 2',
  'item3' => 'Item 3',
  'item4' => 'Item 4'
);
$selected_items = selectByKey(array(
  "item4",
  "item2"
),$all_items);

You will be able to not only select (and filter) custom array items, but to sort it the way you want and use array items few times if needed.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.