I base my example on the assumption that all people are Users (Element type User). If users are entries, you'd have to replace users by entries ;)
I don't think there's a way to do this without iterating through all users first, creating some sort of ordering attribute (if lastName != '' ? lastName : firstName
). Then, you'd be able to group your array by your ordering attribute:
{# create a variable to hold all user data you need #}
{% set allUsers = [] %}
{# loop through users ... #}
{% for user in craft.users.find() %}
{#
... and set variable for each user, containing the info you need
and an 'orderMeBy' attribute, set to the uppercased first character of lastName or firstName
#}
{% set thisUser = [{
fullName : user.fullName,
orderMeBy : user.lastName != '' ? user.lastName | slice(0,1) | upper : user.firstName | slice(0,1) | upper
}] %}
{# merge this user's info with your allUsers variable #}
{% set allUsers = allUsers | merge (thisUser) %}
{% endfor %}
{# group 'allUsers' variable by 'orderMeBy' attribute #}
{% set groupedUsers = allUsers | group('orderMeBy') %}
{# create an array of all numbers and letters #}
{% set numbers = 0..9 %}
{% set letters = 'A'..'Z' %}
{% set allChars = numbers | merge(letters) %}
{# loop to chars and, if users in groupedUsers[char], display those users #}
{% for char in allChars %}
{% if groupedUsers[char] is defined %}
<h2>{{ char }}</h2>
<ul>
{% for user in groupedUsers[char] %}
<li>{{ user.fullName }}</li>
{% endfor %}
</ul>
{% endif %}
{% endfor %}
If anyone knows a quicker and/or easier way, tell me :)