Using setup_postdata() with multi-dimensional array

There was a similar (related) question on here recently. The upshot is that get_the_title() uses the global $post when no argument is passed. And setup_postdata() doesn’t set that global (a mistake I’ve made before now ).

In your case, I would do the following:

foreach( $locations as $post ) {
    setup_postdata(get_post($post['id']));

    echo get_the_title($post['id']);

}
wp_reset_postdata();

Note: setup_postdata() takes a post object, not ID, so if you’re going to use it, use it with get_post().