OK, @HughBP , I've had forty winks ... what you see below is two initial, quick steps before a single, frugal, Apply to each.
One 'Apply to each' With A Small Footprint
The one big assumption that I've made from your example data is that you're running this once per day, for that day's hours. I've added an addendum to cope with the eventuality that you're not.

This can work anywhere in your existing flow, I've used arrayCNST to represent the entirety of your current flow which provides the example data you gave. So any references to that you'd want to obviously replace with your own array.
Part 1 - The Setup
Firstly, you setup an array of names, and an empty array.
Initialize realArrayVAR
The empty array is easily handled with a variable.
Select Names
The array of names is just simple Select action leaving you with an array of names, in your case, multiple David and Amy values!
So those need to be distilled down to just the names, with no duplicates, that will be handled in the first part of ...
Part 2 - The Apply to each
Here, you run an Apply to each on a union() of the array of names to filter down to just the names required.
This drastically reduces any loops by reducing any duplicate names:
union(body('Select_Names'), body('Select_Names'))
So from this example you'd be left with:
[
{
"Name": "David Henderson"
},
{
"Name": "Amy Moran"
}
]
Filter
So, now that you're inside that loop, the first step is to use a Filter action on the original array, to filter to only the current name. This would produce, for example:
[
{
"Name": "David Henderson",
"Weekday": "Tuesday",
"Hours": "1.00000000000000"
},
{
"Name": "David Henderson",
"Weekday": "Tuesday",
"Hours": "1.00000000000000"
},
{
"Name": "David Henderson",
"Weekday": "Tuesday",
"Hours": "2.00000000000000"
},
{
"Name": "David Henderson",
"Weekday": "Tuesday",
"Hours": "1.00000000000000"
}
]
jsonObject
Now that needs to be summed up in an object to be placed into your new, simpler, array, so let's construct that object in a Compose action, I called it jsonObject, with this basic format:
{
"Name": "string",
"Hours": 0000
}
If you want to skip this action you can, as per the note you see on my Append to array action.
The name just takes the name from this Apply to each run with a simple "items('Apply_to_each')?['Name']" expression.
In order to work out the hours, though, you need to do some more complicated work. So, thanks to @takolota's prompting, and this blog, there's a nice xpath() calculation to get the hours. This is the long expression is used to calculate that (int() is now float() to allow partial hours):
float(
xpath(
xml(
json(
concat(
'{"r":{"v":',
body('Filter_array'),
'}}'
)
)
),
'sum(//v/Hours/text()[number(.) = number(.)])'
)
)
The xpath() function takes the Filter action data, ensures the hours are numbers, and adds them all up! The json(concat()) is just wrapping the filter into a structure that the xml() function can understand.
That produces the following final output:
[
{
"Name": "David Henderson",
"Hours": 5
},
{
"Name": "Amy Moran",
"Hours": 3
}
]
As you might be able to guess, I can probably make one with no Apply to each stage after my interview. But this should suffice.
I also left the original code for the Append to array action, which does away with the need for the jsonObject Compose action.
Addendum
Oh, and if you wish to do multiple days, you can just add in the additional logic either around, or inside the Apply to each.
Spoiler (Highlight to read)
Adding it around, for example, wouldn't add that much additional working for the flow. You would just need to do a parallel select on the days, and union() them together in a new Apply to each, and drag the existing one right in there.
Your final result will look something like this:
[
{
"Name": "David Henderson",
"Weekday": "Tuesday",
"Hours": 16
},
{
"Name": "Amy Moran",
"Weekday": "Tuesday",
"Hours": 9.5
},
{
"Name": "David Henderson",
"Weekday": "Wednesday",
"Hours": 16
},
{
"Name": "Amy Moran",
"Weekday": "Wednesday",
"Hours": 9.5
}
]
But you could completely have that be an array of two days, each with their own array of entries, if you liked. It would just require an extra array variable, and a bit of cleansing on each 'daily' loop.
Adding it around, for example, wouldn't add that much additional working for the flow. You would just need to do a parallel select on the days, and union() them together in a new Apply to each, and drag the existing one right in there.
Your final result will look something like this:
[
{
"Name": "David Henderson",
"Weekday": "Tuesday",
"Hours": 16
},
{
"Name": "Amy Moran",
"Weekday": "Tuesday",
"Hours": 9.5
},
{
"Name": "David Henderson",
"Weekday": "Wednesday",
"Hours": 16
},
{
"Name": "Amy Moran",
"Weekday": "Wednesday",
"Hours": 9.5
}
]
But you could completely have that be an array of two days, each with their own array of entries, if you liked. It would just require an extra array variable, and a bit of cleansing on each 'daily' loop.