Centroid of a set of N-dimensional points: Difference between revisions

From Rosetta Code
Content added Content deleted
(Added Wren)
(Added Sidef)
 
(18 intermediate revisions by 9 users not shown)
Line 27: Line 27:
;; [[https://mathworld.wolfram.com/GeometricCentroid.html Wolfram Mathworld on Centroid]]
;; [[https://mathworld.wolfram.com/GeometricCentroid.html Wolfram Mathworld on Centroid]]



=={{header|ALGOL 68}}==
<syntaxhighlight lang="algol68">
BEGIN # find the centroid of some N-dimensional points #

# returns the centroid of points #
OP CENTROID = ( [,]REAL points )[]REAL:
BEGIN
INT number of points = ( 1 UPB points - 1 LWB points ) + 1;
[ 2 LWB points : 2 UPB points ]REAL result;
FOR j FROM 2 LWB points TO 2 UPB points DO
REAL sum := 0;
FOR i FROM 1 LWB points TO 1 UPB points DO sum +:= points[ i, j ] OD;
result[ j ] := sum / number of points
OD;
result
END # CENTROID # ;

OP A = ( INT v )[]REAL: v; # coerces v to []REAL #
OP FMT = ( REAL v )STRING: # formsts v with up to 2 decimals #
BEGIN
STRING result := fixed( v, -0, 2 );
IF result[ LWB result ] = "." THEN "0" +=: result FI;
WHILE result[ UPB result ] = "0" DO result := result[ : UPB result - 1 ] OD;
IF result[ UPB result ] = "." THEN result := result[ : UPB result - 1 ] FI;
" " + result
END # FMT # ;
OP SHOW = ( []REAL v )VOID: # show a 1D array (row) of reals #
BEGIN
print( ( "[" ) );
FOR i FROM LWB v TO UPB v DO print( ( FMT v[ i ] ) ) OD;
print( ( " ]" ) )
END # SHOW # ;
OP SHOW = ( [,]REAL v )VOID: # show a 2D array of reals #
BEGIN
print( ( "[" ) );
FOR i FROM 1 LWB v TO 1 UPB v DO SHOW v[ i, : ] OD;
print( ( "]" ) )
END # SHOW # ;

# task test cases #

PROC test = ( [,]REAL points )VOID: # test the CENTROID operator #
BEGIN SHOW points; print( ( " -> " ) );
SHOW CENTROID points; print( ( newline ) )
END # test # ;

test( ( A(1), A(2), A(3) ) );
test( ( ( 8, 2 ), ( 0, 0 ) ) );
test( ( ( 5, 5, 0 ), ( 10, 10, 0 ) ) );
test( ( ( 1, 3.1, 6.5 ), ( -2, -5, 3.4 )
, ( -7, -4, 9 ), ( 2, 0, 3 )
)
);
test( ( ( 0, 0, 0, 0, 1 ), ( 0, 0, 0, 1, 0 )
, ( 0, 0, 1, 0, 0 ), ( 0, 1, 0, 0, 0 )
)
)

END
</syntaxhighlight>
{{out}}
<pre>
[[ 1 ][ 2 ][ 3 ]] -> [ 2 ]
[[ 8 2 ][ 0 0 ]] -> [ 4 1 ]
[[ 5 5 0 ][ 10 10 0 ]] -> [ 7.5 7.5 0 ]
[[ 1 3.1 6.5 ][ -2 -5 3.4 ][ -7 -4 9 ][ 2 0 3 ]] -> [ -1.5 -1.47 5.47 ]
[[ 0 0 0 0 1 ][ 0 0 0 1 0 ][ 0 0 1 0 0 ][ 0 1 0 0 0 ]] -> [ 0 0.25 0.25 0.25 0.25 ]
</pre>

=={{header|ALGOL W}}==
<syntaxhighlight lang="algolw">
begin % find the centroid of some N dimensional points %

% sets cPoints to the centroid of points %
procedure centroid( real array points ( *, * )
; integer value numberOfPoints, dimension
; real array cPoint ( * )
) ;
for j := 1 until dimension do begin
real sum;
sum := 0;
for i := 1 until numberOfpoints do sum := sum + points( i, j );
cPoint( j ) := sum / numberOfPoints
end centroid ;

begin % task test cases %

% show a real number with two decimal places if if is not integral %
procedure show ( real value rValue ) ;
begin
integer iValue;
iValue := truncate( rValue );
if iValue = rValue then writeon( s_w := 0, i_w := 1, " ", iValue )
else writeon( s_w := 0
, r_format := "A", r_w := 4, r_d := 2
, " ", rValue
)
end show ;

procedure testCentroid( real array points ( *, * )
; integer value numberOfPoints, dimension
) ;
begin
real array cPoint( 1 :: dimension );
centroid( points, numberOfPoints, dimension, cPoint );
write( "[" );
for i := 1 until numberOfPoints do begin
writeon( "[" );
for j := 1 until dimension do show( points( i, j ) );
writeon( " ]" );
end for_i ;
writeon( "] -> [" );
for j := 1 until dimension do show( cPoint( j ) );
writeon( " ]" )
end testCentroid ;

real array p1 ( 1 :: 3, 1 :: 1 ); real array p2 ( 1 :: 2, 1 :: 2 );
real array p3 ( 1 :: 2, 1 :: 3 ); real array p4 ( 1 :: 4, 1 :: 3 );
real array p5 ( 1 :: 4, 1 :: 5 );

p1( 1, 1 ) := 1; p1( 2, 1 ) := 2; p1( 3, 1 ) := 3;
p2( 1, 1 ) := 8; p2( 1, 2 ) := 2;
p2( 2, 1 ) := 0; p2( 2, 2 ) := 0;
p3( 1, 1 ) := 5; p3( 1, 2 ) := 5; p3( 1, 3 ) := 0;
p3( 2, 1 ) := 10; p3( 2, 2 ) := 10; p3( 2, 3 ) := 0;
p4( 1, 1 ) := 1; p4( 1, 2 ) := 3.1; p4( 1, 3 ) := 6.5;
p4( 2, 1 ) := -2; p4( 2, 2 ) := -5; p4( 2, 3 ) := 3.4;
p4( 3, 1 ) := -7; p4( 3, 2 ) := -4; p4( 3, 3 ) := 9;
p4( 4, 1 ) := 2; p4( 4, 2 ) := 0; p4( 4, 3 ) := 3;
p5( 1, 1 ) := 0; p5( 1, 2 ) := 0; p5( 1, 3 ) := 0; p5( 1, 4 ) := 0; p5( 1, 5 ) := 1;
p5( 2, 1 ) := 0; p5( 2, 2 ) := 0; p5( 2, 3 ) := 0; p5( 2, 4 ) := 1; p5( 2, 5 ) := 0;
p5( 3, 1 ) := 0; p5( 3, 2 ) := 0; p5( 3, 3 ) := 1; p5( 3, 4 ) := 0; p5( 3, 5 ) := 0;
p5( 4, 1 ) := 0; p5( 4, 2 ) := 1; p5( 4, 3 ) := 0; p5( 4, 4 ) := 0; p5( 4, 5 ) := 0;

testCentroid( p1, 3, 1 );
testCentroid( p2, 2, 2 );
testCentroid( p3, 2, 3 );
testCentroid( p4, 4, 3 );
testCentroid( p5, 4, 5 )

end

end.</syntaxhighlight>
{{out}}
<pre>[[ 1 ][ 2 ][ 3 ]] -> [ 2 ]
[[ 8 2 ][ 0 0 ]] -> [ 4 1 ]
[[ 5 5 0 ][ 10 10 0 ]] -> [ 7.50 7.50 0 ]
[[ 1 3.10 6.50 ][ -2 -5 3.40 ][ -7 -4 9 ][ 2 0 3 ]] -> [ -1.50 -1.47 5.47 ]
[[ 0 0 0 0 1 ][ 0 0 0 1 0 ][ 0 0 1 0 0 ][ 0 1 0 0 0 ]] -> [ 0 0.25 0.25 0.25 0.25 ]</pre>

=={{header|BASIC256}}==
{{trans|FreeBASIC}}
<syntaxhighlight lang="vb">subroutine Centroid(n, d, pts)
dim ctr(d)

for j = 0 to d-1
ctr[j] = 0
for i = 0 to n-1
ctr[j] += pts[i,j]
next
ctr[j] /= n
next
print "{";
for i = 0 to n-1
print "{";
for j = 0 to d-1
print pts[i,j];
if j < d-1 then print ", ";
next
print "}";
if i < n-1 then print ", ";
next
print "} => Centroid: {";
for j = 0 to d-1
print ctr[j];
if j < d-1 then print ", ";
next
print "}"
end subroutine

pts1 = {{1}, {2}, {3}}
pts2 = {{8, 2}, {0, 0}}
pts3 = {{5, 5, 0}, {10, 10, 0}}
pts4 = {{1, 3.1, 6.5}, {-2, -5, 3.4}, {-7, -4, 9}, {2, 0, 3}}
pts5 = {{0, 0, 0, 0, 1}, {0, 0, 0, 1, 0}, {0, 0, 1, 0, 0}, {0, 1, 0, 0, 0}}

call Centroid(3, 1, pts1)
call Centroid(2, 2, pts2)
call Centroid(2, 3, pts3)
call Centroid(4, 3, pts4)
call Centroid(4, 5, pts5)
end</syntaxhighlight>
{{out}}
<pre>Similar to FreeBASIC entry.</pre>

=={{header|C}}==
The image will, of course, be the same as Wren and Go when the relevant points are fed into Gnuplot.
<syntaxhighlight lang="c">#include <stdio.h>

void centroid(int n, int d, double pts[n][d]) {
int i, j;
double ctr[d];
for (j = 0; j < d; ++j) {
ctr[j] = 0.0;
for (i = 0; i < n; ++i) {
ctr[j] += pts[i][j];
}
ctr[j] /= n;
}
printf("{");
for (i = 0; i < n; ++i) {
printf("{");
for (j = 0; j < d; ++j) {
printf("%g", pts[i][j]);
if (j < d -1) printf(", ");
}
printf("}");
if (i < n - 1) printf(", ");
}
printf("} => Centroid: {");
for (j = 0; j < d; ++j) {
printf("%g", ctr[j]);
if (j < d-1) printf(", ");
}
printf("}\n");
}

int main() {
double pts1[3][1] = { {1}, {2}, {3} };
double pts2[2][2] = { {8, 2}, {0, 0} };
double pts3[2][3] = { {5, 5, 0}, {10, 10, 0} };
double pts4[4][3] = { {1, 3.1, 6.5}, {-2, -5, 3.4}, {-7, -4, 9}, {2, 0, 3} };
double pts5[4][5] = { {0, 0, 0, 0, 1}, {0, 0, 0, 1, 0}, {0, 0, 1, 0, 0}, {0, 1, 0, 0, 0} };

centroid(3, 1, pts1);
centroid(2, 2, pts2);
centroid(2, 3, pts3);
centroid(4, 3, pts4);
centroid(4, 5, pts5);
return 0;
}</syntaxhighlight>

{{out}}
<pre>
{{1}, {2}, {3}} => Centroid: {2}
{{8, 2}, {0, 0}} => Centroid: {4, 1}
{{5, 5, 0}, {10, 10, 0}} => Centroid: {7.5, 7.5, 0}
{{1, 3.1, 6.5}, {-2, -5, 3.4}, {-7, -4, 9}, {2, 0, 3}} => Centroid: {-1.5, -1.475, 5.475}
{{0, 0, 0, 0, 1}, {0, 0, 0, 1, 0}, {0, 0, 1, 0, 0}, {0, 1, 0, 0, 0}} => Centroid: {0, 0.25, 0.25, 0.25, 0.25}
</pre>

=={{header|FreeBASIC}}==
{{trans|XPL0}}
<syntaxhighlight lang="vb">Sub Centroid(n As Ubyte, d As Ubyte, pts() As Single)
Dim As Ubyte i, j
Dim As Single ctr(d)
For j = 0 To d-1
ctr(j) = 0
For i = 0 To n-1
ctr(j)+ = pts(i,j)
Next
ctr(j) /= n
Next
Print "{";
For i = 0 To n-1
Print "{";
For j = 0 To d-1
Print Using "&"; pts(i,j);
If j < d-1 Then Print ", ";
Next
Print "}";
If i < n-1 Then Print ", ";
Next
Print "} => Centroid: {";
For j = 0 To d-1
Print Using "&"; ctr(j);
If j < d-1 Then Print ", ";
Next
Print "}"
End Sub

Dim pts1(2, 1) As Single = {{1}, {2}, {3}}
Dim pts2(1, 1) As Single = {{8, 2}, {0, 0}}
Dim pts3(1, 2) As Single = {{5, 5, 0}, {10, 10, 0}}
Dim pts4(3, 2) As Single = {{1, 3.1, 6.5}, {-2, -5, 3.4}, {-7, -4, 9}, {2, 0, 3}}
Dim pts5(3, 4) As Single = {{0, 0, 0, 0, 1}, _
{0, 0, 0, 1, 0}, {0, 0, 1, 0, 0}, {0, 1, 0, 0, 0}}

Centroid(3, 1, pts1())
Centroid(2, 2, pts2())
Centroid(2, 3, pts3())
Centroid(4, 3, pts4())
Centroid(4, 5, pts5())

Sleep</syntaxhighlight>
{{out}}
<pre>{{1}, {2}, {3}} => Centroid: {2}
{{8, 2}, {0, 0}} => Centroid: {4, 1}
{{5, 5, 0}, {10, 10, 0}} => Centroid: {7.5, 7.5, 0}
{{1, 3.1, 6.5}, {-2, -5, 3.4}, {-7, -4, 9}, {2, 0, 3}} => Centroid: {-1.5, -1.475, 5.475}
{{0, 0, 0, 0, 1}, {0, 0, 0, 1, 0}, {0, 0, 1, 0, 0}, {0, 1, 0, 0, 0}} => Centroid: {0, 0.25, 0.25, 0.25, 0.25}</pre>

=={{header|Go}}==
{{trans|Wren}}
The image will, of course, be the same as Wren when the relevant points are fed into Gnuplot.
<syntaxhighlight lang="go">package main

import (
"fmt"
"log"
)

func centroid(pts [][]float64) []float64 {
n := len(pts)
if n == 0 {
log.Fatal("Slice must contain at least one point.")
}
d := len(pts[0])
for i := 1; i < n; i++ {
if len(pts[i]) != d {
log.Fatal("Points must all have the same dimension.")
}
}
res := make([]float64, d)
for j := 0; j < d; j++ {
for i := 0; i < n; i++ {
res[j] += pts[i][j]
}
res[j] /= float64(n)
}
return res
}

func main() {
points := [][][]float64{
{{1}, {2}, {3}},
{{8, 2}, {0, 0}},
{{5, 5, 0}, {10, 10, 0}},
{{1, 3.1, 6.5}, {-2, -5, 3.4}, {-7, -4, 9}, {2, 0, 3}},
{{0, 0, 0, 0, 1}, {0, 0, 0, 1, 0}, {0, 0, 1, 0, 0}, {0, 1, 0, 0, 0}},
}
for _, pts := range points {
fmt.Println(pts, "=> Centroid:", centroid(pts))
}
}</syntaxhighlight>

{{out}}
<pre>
[[1] [2] [3]] => Centroid: [2]
[[8 2] [0 0]] => Centroid: [4 1]
[[5 5 0] [10 10 0]] => Centroid: [7.5 7.5 0]
[[1 3.1 6.5] [-2 -5 3.4] [-7 -4 9] [2 0 3]] => Centroid: [-1.5 -1.475 5.475]
[[0 0 0 0 1] [0 0 0 1 0] [0 0 1 0 0] [0 1 0 0 0]] => Centroid: [0 0.25 0.25 0.25 0.25]
</pre>

=={{header|jq}}==
{{works with|jq}}
'''Also works with gojq, the Go implementation of jq.'''

With a trivial change to the last line (the one using string interpolation), the following also works with jaq, the Rust implementation of jq.
<syntaxhighlight lang="jq">
# Input: an array of points of the same dimension (i.e. numeric arrays of the same length)
def centroid:
length as $n
| if ($n == 0) then "centroid: list must contain at least one point." | error else . end
| (.[0]|length) as $d
| if any( .[]; length != $d )
then "centroid: points must all have the same dimension." | error
else .
end
| transpose
| map( add / $n ) ;

def points: [
[ [1], [2], [3] ],
[ [8, 2], [0, 0] ],
[ [5, 5, 0], [10, 10, 0] ],
[ [1, 3.1, 6.5], [-2, -5, 3.4], [-7, -4, 9], [2, 0, 3] ],
[ [0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0] ]
];

points[]
| "\(.) => Centroid: \(centroid)"
</syntaxhighlight>
{{output}}
Essentially as for [[#Wren|Wren]].


=={{header|Julia}}==
=={{header|Julia}}==
Line 44: Line 432:


function centroid(arr)
function centroid(arr)
isempty(arr) && return arr
isempty(arr) && return Point{Float64, 0}(arr)
n = length(arr[begin])
n = length(arr[begin])
t = typeof(arr[begin][begin])
t = typeof(arr[begin][begin])
Line 81: Line 469:
</pre>
</pre>
[[File:Plot centroid.png|center|thumb]]
[[File:Plot centroid.png|center|thumb]]

=={{header|Lua}}==
Based on the Algol 68 sample.
<syntaxhighlight lang="lua">
do -- find the centroid of some N-dimensional points

function centroid( points ) -- returns the centroid of points
local result = {}
if #points > 0 then
for j = 1, #points[ 1 ] do
local sum = 0
for i = 1, #points do sum = sum + points[ i ][ j ] end
result[ j ] = sum / #points
end
end
return result
end

function show1d( v ) -- show a 1D array of floats
io.write( "[" )
for i = 1, #v do io.write( " ", v[ i ] ) end
io.write( " ]" )
end
function show2d( v ) -- show a 2D array of floats
io.write( "[" )
for i = 1 , #v do show1d( v[ i ] ) end
io.write( "]" )
end

-- task test cases

function testCentroid( points )
show2d( points )
io.write( " -> " )
show1d( centroid( points ) )
io.write( "\n" )
end

testCentroid{ { 1 }, { 2 }, { 3 } }
testCentroid{ { 8, 2 }, { 0, 0 } }
testCentroid{ { 5, 5, 0 }, { 10, 10, 0 } }
testCentroid{ { 1, 3.1, 6.5 }, { -2, -5, 3.4 }
, { -7, -4, 9 }, { 2, 0, 3 }
}
testCentroid{ { 0, 0, 0, 0, 1 }, { 0, 0, 0, 1, 0 }
, { 0, 0, 1, 0, 0 }, { 0, 1, 0, 0, 0 }
}
end
</syntaxhighlight>
{{out}}
<pre>
[[ 1 ][ 2 ][ 3 ]] -> [ 2 ]
[[ 8 2 ][ 0 0 ]] -> [ 4 1 ]
[[ 5 5 0 ][ 10 10 0 ]] -> [ 7.5 7.5 0 ]
[[ 1 3.1 6.5 ][ -2 -5 3.4 ][ -7 -4 9 ][ 2 0 3 ]] -> [ -1.5 -1.475 5.475 ]
[[ 0 0 0 0 1 ][ 0 0 0 1 0 ][ 0 0 1 0 0 ][ 0 1 0 0 0 ]] -> [ 0 0.25 0.25 0.25 0.25 ]
</pre>

=={{header|Perl}}==
===PDL library, with plot===
{{libheader|PDL}}
<syntaxhighlight lang="perl">use v5.36;
use PDL;

sub centroid ($LoL) {
return pdl($LoL)->transpose->average;
}

sub plot_with_centroid ($LoL) {
require PDL::Graphics::Gnuplot;
my $p = pdl($LoL);
my $pc = $p->glue(1, centroid($p));
my @xyz = map { $pc->slice("($_)") } 0..2;

my $colors = [8,8,8,8,7];

PDL::Graphics::Gnuplot->new('png')->plot3d(
square => 1,
grid => [qw<xtics ytics ztics>],
{ with => 'points', pt => 7, ps => 2, linecolor => 'variable', },
@xyz, $colors,
);
}

my @tests = (
[ [1,], [2,], [3,] ],
[ [8, 2], [0, 0] ],
[ [5, 5, 0], [10, 10, 0] ],
[ [1, 3.1, 6.5], [-2, -5, 3.4], [-7, -4, 9], [2, 0, 3] ],
[ [0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0] ],
);
say centroid($_) for @tests;
plot_with_centroid($tests[3]);
</syntaxhighlight>
{{out}}
<pre>[2]
[4 1]
[7.5 7.5 0]
[-1.5 -1.475 5.475]
[0 0.25 0.25 0.25 0.25]</pre>
[[File:Centroid_plot_perl.png|center|thumb]]
===Direct calculation===
<syntaxhighlight lang="perl" line>
use v5.36;

sub centroid ($LoL) {
my $n = $#{ $LoL };
my $d = $#{ $LoL->@[0] };
my @C = 0 x ($d+1);
for my $i (0..$d) {
$C[$i] += $LoL->@[$_]->@[$i] for 0..$n;
$C[$i] /= $n+1
}
@C
}

say join ' ', centroid($_) for
[ [1,], [2,], [3,] ],
[ [8, 2], [0, 0] ],
[ [5, 5, 0], [10, 10, 0] ],
[ [1, 3.1, 6.5], [-2, -5, 3.4], [-7, -4, 9], [2, 0, 3] ],
[ [0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0] ];
</syntaxhighlight>
{{out}}
<pre>
2
4 1
7.5 7.5 0
-1.5 -1.475 5.475
0 0.25 0.25 0.25 0.25
</pre>

=={{header|Phix}}==
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">centroid</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">pts</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #7060A8;">apply</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">columnize</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pts</span><span style="color: #0000FF;">),</span><span style="color: #7060A8;">average</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">points</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">2</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">3</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{{</span><span style="color: #000000;">8</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{{</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">6.5</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{-</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.4</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{-</span><span style="color: #000000;">7</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">}}}</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">p</span> <span style="color: #008080;">in</span> <span style="color: #000000;">points</span> <span style="color: #008080;">do</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%v ==&gt; Centroid: %v\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">p</span><span style="color: #0000FF;">,</span><span style="color: #000000;">centroid</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">)})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
{{1},{2},{3}} ==> Centroid: {2}
{{8,2},{0,0}} ==> Centroid: {4,1}
{{5,5,0},{10,10,0}} ==> Centroid: {7.5,7.5,0}
{{1,3.1,6.5},{-2,-5,3.4},{-7,-4,9},{2,0,3}} ==> Centroid: {-1.5,-1.475,5.475}
{{0,0,0,0,1},{0,0,0,1,0},{0,0,1,0,0},{0,1,0,0,0}} ==> Centroid: {0,0.25,0.25,0.25,0.25}
</pre>

=={{header|Raku}}==
<syntaxhighlight lang="raku" line>sub centroid { ( [»+«] @^LoL ) »/» +@^LoL }

say .&centroid for
( (1,), (2,), (3,) ),
( (8, 2), (0, 0) ),
( (5, 5, 0), (10, 10, 0) ),
( (1, 3.1, 6.5), (-2, -5, 3.4), (-7, -4, 9), (2, 0, 3) ),
( (0, 0, 0, 0, 1), (0, 0, 0, 1, 0), (0, 0, 1, 0, 0), (0, 1, 0, 0, 0) ),
;
</syntaxhighlight>
{{out}}
<pre>(2)
(4 1)
(7.5 7.5 0)
(-1.5 -1.475 5.475)
(0 0.25 0.25 0.25 0.25)</pre>

=={{header|Sidef}}==

<syntaxhighlight lang="ruby">func centroid(l) {
l.combine {|*a| a.sum } »/» l.len
}

[
[ [1], [2], [3] ],
[ [8, 2], [0, 0] ],
[ [5, 5, 0], [10, 10, 0] ],
[ [1, 3.1, 6.5], [-2, -5, 3.4], [-7, -4, 9], [2, 0, 3] ],
[ [0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0] ],
].each {
say centroid(_)
}</syntaxhighlight>

{{out}}
<pre>
[2]
[4, 1]
[15/2, 15/2, 0]
[-3/2, -59/40, 219/40]
[0, 1/4, 1/4, 1/4, 1/4]
</pre>


=={{header|Wren}}==
=={{header|Wren}}==
<syntaxhighlight lang="ecmascript">var centroid = Fn.new { |pts|
<syntaxhighlight lang="wren">var centroid = Fn.new { |pts|
var n = pts.count
var n = pts.count
if (n == 0) Fiber.abort("List must contain at least one point.")
var d = pts[0].count
var d = pts[0].count
if (pts.skip(1).any { |p| p.count != d }) {
Fiber.abort("Points must all have the same dimension.")
}
var res = List.filled(d, 0)
var res = List.filled(d, 0)
for (j in 0...d) {
for (j in 0...d) {
Line 116: Line 707:
[[0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0]] => Centroid: [0, 0.25, 0.25, 0.25, 0.25]
[[0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0]] => Centroid: [0, 0.25, 0.25, 0.25, 0.25]
</pre>
</pre>

{{libheader|Wren-seq}}
{{libheader|Wren-math}}
Or, more concise using library methods - output identical.
<syntaxhighlight lang="wren">import "./seq" for Lst
import "./math" for Nums

var centroid = Fn.new { |pts|
return Lst.columns(pts).map { |c| Nums.mean(c) }.toList
}

var points = [
[ [1], [2], [3] ],
[ [8, 2], [0, 0] ],
[ [5, 5, 0], [10, 10, 0] ],
[ [1, 3.1, 6.5], [-2, -5, 3.4], [-7, -4, 9], [2, 0, 3] ],
[ [0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0] ]
]

for (pts in points) {
System.print("%(pts) => Centroid: %(centroid.call(pts))")
}</syntaxhighlight>

[[File:wren-centroid.png|center|thumb]]
[[File:wren-centroid.png|center|thumb]]

=={{header|XPL0}}==
{{trans|C}}
<syntaxhighlight lang "XPL0">include xpllib; \for Print

proc Centroid(N, D, Pts);
int N, D; real Pts;
int I, J;
real Ctr;
[Ctr:= RlRes(D);
for J:= 0 to D-1 do
[Ctr(J):= 0.0;
for I:= 0 to N-1 do
Ctr(J):= Ctr(J) + Pts(I,J);
Ctr(J):= Ctr(J) / float(N);
];
Print("[");
for I:= 0 to N-1 do
[Print("[");
for J:= 0 to D-1 do
[Print("%g", Pts(I,J));
if J < D-1 then Print(", ");
];
Print("]");
if I < N-1 then Print(", ");
];
Print("] => Centroid: [");
for J:= 0 to D-1 do
[Print("%g", Ctr(J));
if J < D-1 then Print(", ");
];
Print("]\n");
];

real Pts1, Pts2, Pts3, Pts4, Pts5;
[Pts1:= [ [1.], [2.], [3.] ];
Pts2:= [ [8., 2.], [0., 0.] ];
Pts3:= [ [5., 5., 0.], [10., 10., 0.] ];
Pts4:= [ [1., 3.1, 6.5], [-2., -5., 3.4], [-7., -4., 9.], [2., 0., 3.] ];
Pts5:= [ [0., 0., 0., 0., 1.], [0., 0., 0., 1., 0.], [0., 0., 1., 0., 0.],
[0., 1., 0., 0., 0.] ];
Centroid(3, 1, Pts1);
Centroid(2, 2, Pts2);
Centroid(2, 3, Pts3);
Centroid(4, 3, Pts4);
Centroid(4, 5, Pts5);
]</syntaxhighlight>
{{out}}
<pre>
[[1], [2], [3]] => Centroid: [2]
[[8, 2], [0, 0]] => Centroid: [4, 1]
[[5, 5, 0], [10, 10, 0]] => Centroid: [7.5, 7.5, 0]
[[1, 3.1, 6.5], [-2, -5, 3.4], [-7, -4, 9], [2, 0, 3]] => Centroid: [-1.5, -1.475, 5.475]
[[0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0]] => Centroid: [0, 0.25, 0.25, 0.25, 0.25]
</pre>

Latest revision as of 15:14, 15 December 2023

Centroid of a set of N-dimensional points is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

In analytic geometry, the centroid of a set of points is a point in the same domain as the set. The centroid point is chosen to show a property which can be calculated for that set.

Consider the centroid defined as the arithmetic mean of a set of points of arbitrary dimension.

Task

Create a function in your chosen programming language to calculate such a centroid using an arbitrary number of points of arbitrary dimension.

Test your function with the following groups of points
one-dimensional: (1), (2), (3)
two-dimensional: (8, 2), (0, 0)
three-dimensional: the set (5, 5, 0), (10, 10, 0) and the set (1, 3.1, 6.5), (-2, -5, 3.4), (-7, -4, 9), (2, 0, 3)
five-dimensional: (0, 0, 0, 0, 1), (0, 0, 0, 1, 0), (0, 0, 1, 0, 0), (0, 1, 0, 0, 0)


Stretch task
   Show a 3D plot image of the second 3-dimensional set and its centroid.
See Also
[Wikipedia page]
[Wolfram Mathworld on Centroid]


ALGOL 68

BEGIN # find the centroid of some N-dimensional points                       #

    # returns the centroid of points                                         #
    OP   CENTROID = ( [,]REAL points )[]REAL:
         BEGIN
            INT number of points = ( 1 UPB points - 1 LWB points ) + 1;
            [ 2 LWB points : 2 UPB points ]REAL result;
            FOR j FROM 2 LWB points TO 2 UPB points DO
                REAL sum := 0;
                FOR i FROM 1 LWB points TO 1 UPB points DO sum +:= points[ i, j ] OD;
                result[ j ] := sum / number of points
            OD;
            result
         END # CENTROID # ;

    OP   A         = ( INT  v )[]REAL: v;              # coerces v to []REAL #
    OP   FMT       = ( REAL v )STRING:     # formsts v with up to 2 decimals #
         BEGIN
            STRING result := fixed( v, -0, 2 );
            IF result[ LWB result ] = "." THEN "0" +=: result FI;
            WHILE result[ UPB result ] = "0" DO result := result[ : UPB result - 1 ] OD;
            IF result[ UPB result ] = "." THEN result := result[ : UPB result - 1 ] FI;
            " " + result
         END # FMT # ; 
    OP   SHOW      = ( []REAL v )VOID:      # show a 1D array (row) of reals #
         BEGIN
            print( ( "[" ) );
            FOR i FROM LWB v TO UPB v DO print( ( FMT v[ i ] ) ) OD;
            print( ( " ]" ) )
         END # SHOW # ;
    OP   SHOW      = ( [,]REAL v )VOID:           # show a 2D array of reals #
         BEGIN
            print( ( "[" ) );
            FOR i FROM 1 LWB v TO 1 UPB v DO SHOW v[ i, : ] OD;
            print( ( "]" ) )
         END # SHOW # ;

    # task test cases                                                        #

    PROC test = ( [,]REAL points )VOID:         # test the CENTROID operator #
         BEGIN SHOW          points; print( ( "   -> " ) );
               SHOW CENTROID points; print( ( newline ) )
         END # test # ;

    test( ( A(1), A(2), A(3) ) );
    test( ( ( 8, 2 ), ( 0, 0 ) ) );
    test( ( ( 5, 5, 0 ), ( 10, 10, 0 ) ) );
    test( ( (  1, 3.1, 6.5 ), ( -2, -5, 3.4 )
          , ( -7,  -4, 9   ), (  2,  0,   3 )
          )
        );
    test( ( ( 0, 0, 0, 0, 1 ), ( 0, 0, 0, 1, 0 )
          , ( 0, 0, 1, 0, 0 ), ( 0, 1, 0, 0, 0 )
          )
        )

END
Output:
[[ 1 ][ 2 ][ 3 ]]   -> [ 2 ]
[[ 8 2 ][ 0 0 ]]   -> [ 4 1 ]
[[ 5 5 0 ][ 10 10 0 ]]   -> [ 7.5 7.5 0 ]
[[ 1 3.1 6.5 ][ -2 -5 3.4 ][ -7 -4 9 ][ 2 0 3 ]]   -> [ -1.5 -1.47 5.47 ]
[[ 0 0 0 0 1 ][ 0 0 0 1 0 ][ 0 0 1 0 0 ][ 0 1 0 0 0 ]]   -> [ 0 0.25 0.25 0.25 0.25 ]

ALGOL W

begin % find the centroid of some N dimensional points                       %

    % sets cPoints to the centroid of points                                 %
    procedure centroid( real array points ( *, * )
                      ; integer value numberOfPoints, dimension
                      ; real array cPoint ( * )
                      ) ;
    for j := 1 until dimension do begin
        real sum;
        sum := 0;
        for i := 1 until numberOfpoints do sum := sum + points( i, j );
        cPoint( j ) := sum / numberOfPoints
    end centroid ;

    begin % task test cases                                                  %

        % show a real number with two decimal places if if is not integral   %
        procedure show ( real value rValue ) ;
        begin
            integer iValue;
            iValue := truncate( rValue );
            if iValue = rValue then writeon( s_w := 0, i_w := 1, " ", iValue )
                               else writeon( s_w := 0
                                           , r_format := "A", r_w := 4, r_d := 2
                                           , " ", rValue
                                           )
        end show ;

        procedure testCentroid( real array points ( *, * )
                              ; integer value numberOfPoints, dimension
                              ) ;
        begin
            real array cPoint( 1 :: dimension );
            centroid( points, numberOfPoints, dimension, cPoint );
            write( "[" );
            for i := 1 until numberOfPoints do begin
                writeon( "[" );
                for j := 1 until dimension do show( points( i, j ) );
                writeon( " ]" );
            end for_i ;
            writeon( "] -> [" );
            for j := 1 until dimension do show( cPoint( j ) );
            writeon( " ]" )
        end testCentroid ;

        real array p1 ( 1 :: 3, 1 :: 1 ); real array p2 ( 1 :: 2, 1 :: 2 );
        real array p3 ( 1 :: 2, 1 :: 3 ); real array p4 ( 1 :: 4, 1 :: 3 );
        real array p5 ( 1 :: 4, 1 :: 5 );

        p1( 1, 1 ) :=  1;  p1( 2, 1 ) :=   2; p1( 3, 1 ) := 3; 
        p2( 1, 1 ) :=  8;  p2( 1, 2 ) :=   2; 
        p2( 2, 1 ) :=  0;  p2( 2, 2 ) :=   0; 
        p3( 1, 1 ) :=  5;  p3( 1, 2 ) :=   5; p3( 1, 3 ) := 0; 
        p3( 2, 1 ) := 10;  p3( 2, 2 ) :=  10; p3( 2, 3 ) := 0; 
        p4( 1, 1 ) :=  1;  p4( 1, 2 ) := 3.1; p4( 1, 3 ) := 6.5; 
        p4( 2, 1 ) := -2;  p4( 2, 2 ) :=  -5; p4( 2, 3 ) := 3.4; 
        p4( 3, 1 ) := -7;  p4( 3, 2 ) :=  -4; p4( 3, 3 ) := 9; 
        p4( 4, 1 ) :=  2;  p4( 4, 2 ) :=   0; p4( 4, 3 ) := 3; 
        p5( 1, 1 ) :=  0;  p5( 1, 2 ) :=   0; p5( 1, 3 ) := 0;  p5( 1, 4 ) := 0;  p5( 1, 5 ) := 1; 
        p5( 2, 1 ) :=  0;  p5( 2, 2 ) :=   0; p5( 2, 3 ) := 0;  p5( 2, 4 ) := 1;  p5( 2, 5 ) := 0; 
        p5( 3, 1 ) :=  0;  p5( 3, 2 ) :=   0; p5( 3, 3 ) := 1;  p5( 3, 4 ) := 0;  p5( 3, 5 ) := 0; 
        p5( 4, 1 ) :=  0;  p5( 4, 2 ) :=   1; p5( 4, 3 ) := 0;  p5( 4, 4 ) := 0;  p5( 4, 5 ) := 0; 

        testCentroid( p1, 3, 1 );
        testCentroid( p2, 2, 2 );
        testCentroid( p3, 2, 3 );
        testCentroid( p4, 4, 3 );
        testCentroid( p5, 4, 5 )

    end

end.
Output:
[[ 1 ][ 2 ][ 3 ]] -> [ 2 ]
[[ 8 2 ][ 0 0 ]] -> [ 4 1 ]
[[ 5 5 0 ][ 10 10 0 ]] -> [ 7.50 7.50 0 ]
[[ 1 3.10 6.50 ][ -2 -5 3.40 ][ -7 -4 9 ][ 2 0 3 ]] -> [ -1.50 -1.47 5.47 ]
[[ 0 0 0 0 1 ][ 0 0 0 1 0 ][ 0 0 1 0 0 ][ 0 1 0 0 0 ]] -> [ 0 0.25 0.25 0.25 0.25 ]

BASIC256

Translation of: FreeBASIC
subroutine Centroid(n, d, pts)
	dim ctr(d)

	for j = 0 to d-1
		ctr[j] = 0
		for i = 0 to n-1
			ctr[j] += pts[i,j]
		next
		ctr[j] /= n
	next
	print "{";
	for i = 0 to n-1
		print "{";
		for j = 0 to d-1
			print pts[i,j];
			if j < d-1 then print ", ";
		next
		print "}";
		if i < n-1 then print ", ";
	next
	print "} => Centroid: {";
	for j = 0 to d-1
		print ctr[j];
		if j < d-1 then print ", ";
	next
	print "}"
end subroutine

pts1 = {{1}, {2}, {3}}
pts2 = {{8, 2}, {0, 0}}
pts3 = {{5, 5, 0}, {10, 10, 0}}
pts4 = {{1, 3.1, 6.5}, {-2, -5, 3.4}, {-7, -4, 9}, {2, 0, 3}}
pts5 = {{0, 0, 0, 0, 1}, {0, 0, 0, 1, 0}, {0, 0, 1, 0, 0}, {0, 1, 0, 0, 0}}

call Centroid(3, 1, pts1)
call Centroid(2, 2, pts2)
call Centroid(2, 3, pts3)
call Centroid(4, 3, pts4)
call Centroid(4, 5, pts5)
end
Output:
Similar to FreeBASIC entry.

C

The image will, of course, be the same as Wren and Go when the relevant points are fed into Gnuplot.

#include <stdio.h>

void centroid(int n, int d, double pts[n][d]) {
    int i, j;
    double ctr[d];
    for (j = 0; j < d; ++j) {
        ctr[j] = 0.0;
        for (i = 0; i < n; ++i) {
            ctr[j] += pts[i][j];
        }
        ctr[j] /= n;
    }
    printf("{");
    for (i = 0; i < n; ++i) {
        printf("{");
        for (j = 0; j < d; ++j) {
            printf("%g", pts[i][j]);
            if (j < d -1) printf(", ");
        }
        printf("}");
        if (i < n - 1) printf(", ");
    }
    printf("} => Centroid: {");
    for (j = 0; j < d; ++j) {
        printf("%g", ctr[j]);
        if (j < d-1) printf(", ");
    }
    printf("}\n");
}

int main() {
    double pts1[3][1] = { {1}, {2}, {3} };
    double pts2[2][2] = { {8, 2}, {0, 0} };
    double pts3[2][3] = { {5, 5, 0}, {10, 10, 0} };
    double pts4[4][3] = { {1, 3.1, 6.5}, {-2, -5, 3.4}, {-7, -4, 9}, {2, 0, 3} };
    double pts5[4][5] = { {0, 0, 0, 0, 1}, {0, 0, 0, 1, 0}, {0, 0, 1, 0, 0}, {0, 1, 0, 0, 0} };

    centroid(3, 1, pts1);
    centroid(2, 2, pts2);
    centroid(2, 3, pts3);
    centroid(4, 3, pts4);
    centroid(4, 5, pts5);
    return 0;
}
Output:
{{1}, {2}, {3}} => Centroid: {2}
{{8, 2}, {0, 0}} => Centroid: {4, 1}
{{5, 5, 0}, {10, 10, 0}} => Centroid: {7.5, 7.5, 0}
{{1, 3.1, 6.5}, {-2, -5, 3.4}, {-7, -4, 9}, {2, 0, 3}} => Centroid: {-1.5, -1.475, 5.475}
{{0, 0, 0, 0, 1}, {0, 0, 0, 1, 0}, {0, 0, 1, 0, 0}, {0, 1, 0, 0, 0}} => Centroid: {0, 0.25, 0.25, 0.25, 0.25}

FreeBASIC

Translation of: XPL0
Sub Centroid(n As Ubyte, d As Ubyte, pts() As Single)
    Dim As Ubyte i, j
    Dim As Single ctr(d)
    
    For j = 0 To d-1
        ctr(j) = 0
        For i = 0 To n-1
            ctr(j)+ = pts(i,j)
        Next
        ctr(j) /= n
    Next
    Print "{"; 
    For i = 0 To n-1
        Print "{";
        For j = 0 To d-1
            Print Using "&"; pts(i,j);
            If j < d-1 Then Print ", ";
        Next
        Print "}";
        If i < n-1 Then Print ", ";
    Next
    Print "} => Centroid: {";
    For j = 0 To d-1
        Print Using "&"; ctr(j);
        If j < d-1 Then Print ", ";
    Next
    Print "}"
End Sub

Dim pts1(2, 1) As Single = {{1}, {2}, {3}}
Dim pts2(1, 1) As Single = {{8, 2}, {0, 0}}
Dim pts3(1, 2) As Single = {{5, 5, 0}, {10, 10, 0}}
Dim pts4(3, 2) As Single = {{1, 3.1, 6.5}, {-2, -5, 3.4}, {-7, -4, 9}, {2, 0, 3}}
Dim pts5(3, 4) As Single = {{0, 0, 0, 0, 1}, _
{0, 0, 0, 1, 0}, {0, 0, 1, 0, 0}, {0, 1, 0, 0, 0}}

Centroid(3, 1, pts1())
Centroid(2, 2, pts2())
Centroid(2, 3, pts3())
Centroid(4, 3, pts4())
Centroid(4, 5, pts5())

Sleep
Output:
{{1}, {2}, {3}} => Centroid: {2}
{{8, 2}, {0, 0}} => Centroid: {4, 1}
{{5, 5, 0}, {10, 10, 0}} => Centroid: {7.5, 7.5, 0}
{{1, 3.1, 6.5}, {-2, -5, 3.4}, {-7, -4, 9}, {2, 0, 3}} => Centroid: {-1.5, -1.475, 5.475}
{{0, 0, 0, 0, 1}, {0, 0, 0, 1, 0}, {0, 0, 1, 0, 0}, {0, 1, 0, 0, 0}} => Centroid: {0, 0.25, 0.25, 0.25, 0.25}

Go

Translation of: Wren

The image will, of course, be the same as Wren when the relevant points are fed into Gnuplot.

package main

import (
    "fmt"
    "log"
)

func centroid(pts [][]float64) []float64 {
    n := len(pts)
    if n == 0 {
        log.Fatal("Slice must contain at least one point.")
    }
    d := len(pts[0])
    for i := 1; i < n; i++ {
        if len(pts[i]) != d {
            log.Fatal("Points must all have the same dimension.")
        }
    }
    res := make([]float64, d)
    for j := 0; j < d; j++ {
        for i := 0; i < n; i++ {
            res[j] += pts[i][j]
        }
        res[j] /= float64(n)
    }
    return res
}

func main() {
    points := [][][]float64{
        {{1}, {2}, {3}},
        {{8, 2}, {0, 0}},
        {{5, 5, 0}, {10, 10, 0}},
        {{1, 3.1, 6.5}, {-2, -5, 3.4}, {-7, -4, 9}, {2, 0, 3}},
        {{0, 0, 0, 0, 1}, {0, 0, 0, 1, 0}, {0, 0, 1, 0, 0}, {0, 1, 0, 0, 0}},
    }
    for _, pts := range points {
        fmt.Println(pts, "=> Centroid:", centroid(pts))
    }
}
Output:
[[1] [2] [3]] => Centroid: [2]
[[8 2] [0 0]] => Centroid: [4 1]
[[5 5 0] [10 10 0]] => Centroid: [7.5 7.5 0]
[[1 3.1 6.5] [-2 -5 3.4] [-7 -4 9] [2 0 3]] => Centroid: [-1.5 -1.475 5.475]
[[0 0 0 0 1] [0 0 0 1 0] [0 0 1 0 0] [0 1 0 0 0]] => Centroid: [0 0.25 0.25 0.25 0.25]

jq

Works with: jq

Also works with gojq, the Go implementation of jq.

With a trivial change to the last line (the one using string interpolation), the following also works with jaq, the Rust implementation of jq.

# Input: an array of points of the same dimension (i.e. numeric arrays of the same length)
def centroid:
  length as $n
  | if ($n == 0) then "centroid: list must contain at least one point." | error else . end
  | (.[0]|length) as $d
  | if any( .[]; length != $d ) 
    then "centroid: points must all have the same dimension." | error
    else .
    end
  | transpose
  | map( add / $n ) ;

def points: [
    [ [1], [2], [3] ],
    [ [8, 2], [0, 0] ],
    [ [5, 5, 0], [10, 10, 0] ],
    [ [1, 3.1, 6.5], [-2, -5, 3.4], [-7, -4, 9], [2, 0, 3] ],
    [ [0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0] ]
 ];

points[]
| "\(.) => Centroid: \(centroid)"
Output:

Essentially as for Wren.

Julia

using Plots

struct Point{T, N}
    v::Vector{T}
end

function centroid(points::Vector{Point{T, N}}) where N where T
    arr = zeros(T, N)
    for p in points, (i, x) in enumerate(p.v)
        arr[i] += x
    end
    return Point{T, N}(arr / length(points))
end

function centroid(arr)
    isempty(arr) && return Point{Float64, 0}(arr)
    n = length(arr[begin])
    t = typeof(arr[begin][begin])
    return centroid([Point{t, n}(v) for v in arr])
end

const testvecs = [[[1], [2], [3]],
                  [(8, 2), (0, 0)],
                  [[5, 5, 0], [10, 10, 0]],
                  [[1.0, 3.1, 6.5], [-2, -5, 3.4], [-7, -4, 9.0], [2.0, 0.0, 3.0],],
                  [[0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0],],
                 ]

function test_centroids(tests)
    for t in tests
        isempty(t) && error("The empty set of points $t has no centroid")
        vvec = [Point{Float64, length(t[begin])}(collect(v)) for v in t]
        println("$t => $(centroid(vvec))")
    end
    xyz = [p[1] for p in tests[4]], [p[2] for p in tests[4]], [p[3] for p in tests[4]]
    cpoint = centroid(tests[4]).v
    for i in eachindex(cpoint)
        push!(xyz[i], cpoint[i])
    end
    scatter(xyz..., color = [:navy, :navy, :navy, :navy, :red], legend = :none)
end

test_centroids(testvecs)
Output:
[[1], [2], [3]] => Point{Float64, 1}([2.0])
[(8, 2), (0, 0)] => Point{Float64, 2}([4.0, 1.0])
[[5, 5, 0], [10, 10, 0]] => Point{Float64, 3}([7.5, 7.5, 0.0])
[[1.0, 3.1, 6.5], [-2.0, -5.0, 3.4], [-7.0, -4.0, 9.0], [2.0, 0.0, 3.0]] => Point{Float64, 3}([-1.5, -1.475, 5.475])
[[0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0]] => Point{Float64, 5}([0.0, 0.25, 0.25, 0.25, 0.25])

Lua

Based on the Algol 68 sample.

do -- find the centroid of some N-dimensional points

    function centroid( points ) -- returns the centroid of points
         local result = {}
         if #points > 0 then
             for j = 1, #points[ 1 ] do
                 local sum = 0
                 for i = 1, #points do sum = sum + points[ i ][ j ] end
                 result[ j ] = sum / #points
             end
         end
         return result
    end 

    function show1d( v ) -- show a 1D array of floats
        io.write( "[" )
        for i = 1, #v do io.write( " ", v[ i ] ) end
        io.write( " ]" )
    end 
    function show2d( v ) -- show a 2D array of floats
        io.write( "[" )
        for i = 1 , #v do show1d( v[ i ] ) end
        io.write( "]" )
    end 

    -- task test cases

    function testCentroid( points )
         show2d( points )
         io.write( "   -> " )
         show1d( centroid( points ) )
         io.write( "\n" )
    end

    testCentroid{ { 1 }, { 2 }, { 3 } }
    testCentroid{ { 8, 2 }, { 0, 0 } }
    testCentroid{ { 5, 5, 0 }, { 10, 10, 0 } }
    testCentroid{ {  1, 3.1, 6.5 }, { -2, -5, 3.4 }
                , { -7,  -4, 9   }, {  2,  0,   3 }
                }
    testCentroid{ { 0, 0, 0, 0, 1 }, { 0, 0, 0, 1, 0 }
                , { 0, 0, 1, 0, 0 }, { 0, 1, 0, 0, 0 }
                }
end
Output:
[[ 1 ][ 2 ][ 3 ]]   -> [ 2 ]
[[ 8 2 ][ 0 0 ]]   -> [ 4 1 ]
[[ 5 5 0 ][ 10 10 0 ]]   -> [ 7.5 7.5 0 ]
[[ 1 3.1 6.5 ][ -2 -5 3.4 ][ -7 -4 9 ][ 2 0 3 ]]   -> [ -1.5 -1.475 5.475 ]
[[ 0 0 0 0 1 ][ 0 0 0 1 0 ][ 0 0 1 0 0 ][ 0 1 0 0 0 ]]   -> [ 0 0.25 0.25 0.25 0.25 ]

Perl

PDL library, with plot

Library: PDL
use v5.36;
use PDL;

sub centroid ($LoL) {
    return pdl($LoL)->transpose->average;
}

sub plot_with_centroid ($LoL) {
    require PDL::Graphics::Gnuplot;
    my $p   = pdl($LoL);
    my $pc  = $p->glue(1, centroid($p));
    my @xyz = map { $pc->slice("($_)") } 0..2;

    my $colors = [8,8,8,8,7];

    PDL::Graphics::Gnuplot->new('png')->plot3d(
        square => 1,
        grid   => [qw<xtics ytics ztics>],
        { with => 'points', pt => 7, ps => 2, linecolor => 'variable', },
        @xyz, $colors,
    );
}

my @tests = (
    [ [1,], [2,], [3,] ],
    [ [8, 2], [0, 0] ],
    [ [5, 5, 0], [10, 10, 0] ],
    [ [1, 3.1, 6.5], [-2, -5, 3.4], [-7, -4, 9], [2, 0, 3] ],
    [ [0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0] ],
);
say centroid($_) for @tests;
plot_with_centroid($tests[3]);
Output:
[2]
[4 1]
[7.5 7.5 0]
[-1.5 -1.475 5.475]
[0 0.25 0.25 0.25 0.25]

Direct calculation

use v5.36;

sub centroid ($LoL) {
    my $n = $#{ $LoL       };
    my $d = $#{ $LoL->@[0] };
    my @C = 0 x ($d+1);
    for my $i (0..$d) {
        $C[$i] += $LoL->@[$_]->@[$i] for 0..$n;
        $C[$i] /= $n+1
    }
    @C
}

say join ' ', centroid($_) for
    [ [1,], [2,], [3,] ],
    [ [8, 2], [0, 0] ],
    [ [5, 5, 0], [10, 10, 0] ],
    [ [1, 3.1, 6.5], [-2, -5, 3.4], [-7, -4, 9], [2, 0, 3] ],
    [ [0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0] ];
Output:
2
4 1
7.5 7.5 0
-1.5 -1.475 5.475
0 0.25 0.25 0.25 0.25

Phix

with javascript_semantics
function centroid(sequence pts)
    return apply(columnize(pts),average)
end function

constant points = {{{1}, {2}, {3}},
                   {{8, 2}, {0, 0}},
                   {{5, 5, 0}, {10, 10, 0}},
                   {{1, 3.1, 6.5}, {-2, -5, 3.4}, {-7, -4, 9}, {2, 0, 3}},
                   {{0, 0, 0, 0, 1}, {0, 0, 0, 1, 0}, {0, 0, 1, 0, 0}, {0, 1, 0, 0, 0}}}
for p in points do
    printf(1,"%v ==> Centroid: %v\n",{p,centroid(p)})
end for
Output:
{{1},{2},{3}} ==> Centroid: {2}
{{8,2},{0,0}} ==> Centroid: {4,1}
{{5,5,0},{10,10,0}} ==> Centroid: {7.5,7.5,0}
{{1,3.1,6.5},{-2,-5,3.4},{-7,-4,9},{2,0,3}} ==> Centroid: {-1.5,-1.475,5.475}
{{0,0,0,0,1},{0,0,0,1,0},{0,0,1,0,0},{0,1,0,0,0}} ==> Centroid: {0,0.25,0.25,0.25,0.25}

Raku

sub centroid { ( [»+«] @^LoL ) »/» +@^LoL }

say .&centroid for
    ( (1,), (2,), (3,) ),
    ( (8, 2), (0, 0) ),
    ( (5, 5, 0), (10, 10, 0) ),
    ( (1, 3.1, 6.5), (-2, -5, 3.4), (-7, -4, 9), (2, 0, 3) ),
    ( (0, 0, 0, 0, 1), (0, 0, 0, 1, 0), (0, 0, 1, 0, 0), (0, 1, 0, 0, 0) ),
;
Output:
(2)
(4 1)
(7.5 7.5 0)
(-1.5 -1.475 5.475)
(0 0.25 0.25 0.25 0.25)

Sidef

func centroid(l) {
    l.combine {|*a| a.sum } »/» l.len
}

[
    [ [1], [2], [3] ],
    [ [8, 2], [0, 0] ],
    [ [5, 5, 0], [10, 10, 0] ],
    [ [1, 3.1, 6.5], [-2, -5, 3.4], [-7, -4, 9], [2, 0, 3] ],
    [ [0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0] ],
].each {
    say centroid(_)
}
Output:
[2]
[4, 1]
[15/2, 15/2, 0]
[-3/2, -59/40, 219/40]
[0, 1/4, 1/4, 1/4, 1/4]

Wren

var centroid = Fn.new { |pts|
    var n = pts.count
    if (n == 0) Fiber.abort("List must contain at least one point.")
    var d = pts[0].count
    if (pts.skip(1).any { |p| p.count != d }) {
        Fiber.abort("Points must all have the same dimension.")
    }
    var res = List.filled(d, 0)
    for (j in 0...d) {
        for (i in 0...n) {
            res[j] = res[j] + pts[i][j]
        }
        res[j] = res[j] / n
    }
    return res
}

var points = [
    [ [1], [2], [3] ],
    [ [8, 2], [0, 0] ],
    [ [5, 5, 0], [10, 10, 0] ],
    [ [1, 3.1, 6.5], [-2, -5, 3.4], [-7, -4, 9], [2, 0, 3] ],
    [ [0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0] ]
]

for (pts in points) {
    System.print("%(pts) => Centroid: %(centroid.call(pts))")
}
Output:
[[1], [2], [3]] => Centroid: [2]
[[8, 2], [0, 0]] => Centroid: [4, 1]
[[5, 5, 0], [10, 10, 0]] => Centroid: [7.5, 7.5, 0]
[[1, 3.1, 6.5], [-2, -5, 3.4], [-7, -4, 9], [2, 0, 3]] => Centroid: [-1.5, -1.475, 5.475]
[[0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0]] => Centroid: [0, 0.25, 0.25, 0.25, 0.25]
Library: Wren-seq
Library: Wren-math

Or, more concise using library methods - output identical.

import "./seq" for Lst
import "./math" for Nums

var centroid = Fn.new { |pts|
    return Lst.columns(pts).map { |c| Nums.mean(c) }.toList
}

var points = [
    [ [1], [2], [3] ],
    [ [8, 2], [0, 0] ],
    [ [5, 5, 0], [10, 10, 0] ],
    [ [1, 3.1, 6.5], [-2, -5, 3.4], [-7, -4, 9], [2, 0, 3] ],
    [ [0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0] ]
]

for (pts in points) {
    System.print("%(pts) => Centroid: %(centroid.call(pts))")
}

XPL0

Translation of: C
include xpllib;         \for Print

proc Centroid(N, D, Pts);
int  N, D;  real Pts;
int  I, J;
real Ctr;
[Ctr:= RlRes(D);
for J:= 0 to D-1 do
    [Ctr(J):= 0.0;
    for I:= 0 to N-1 do
        Ctr(J):= Ctr(J) + Pts(I,J);
    Ctr(J):= Ctr(J) / float(N);
    ];
Print("[");
for I:= 0 to N-1 do
    [Print("[");
    for J:= 0 to D-1 do
        [Print("%g", Pts(I,J));
        if J < D-1 then Print(", ");
        ];
    Print("]");
    if I < N-1 then Print(", ");
    ];
Print("] => Centroid: [");
for J:= 0 to D-1 do
    [Print("%g", Ctr(J));
    if J < D-1 then Print(", ");
    ];
Print("]\n");
];

real Pts1, Pts2, Pts3, Pts4, Pts5;
[Pts1:= [ [1.], [2.], [3.] ];
 Pts2:= [ [8., 2.], [0., 0.] ];
 Pts3:= [ [5., 5., 0.], [10., 10., 0.] ];
 Pts4:= [ [1., 3.1, 6.5], [-2., -5., 3.4], [-7., -4., 9.], [2., 0., 3.] ];
 Pts5:= [ [0., 0., 0., 0., 1.], [0., 0., 0., 1., 0.], [0., 0., 1., 0., 0.],
          [0., 1., 0., 0., 0.] ];
Centroid(3, 1, Pts1);
Centroid(2, 2, Pts2);
Centroid(2, 3, Pts3);
Centroid(4, 3, Pts4);
Centroid(4, 5, Pts5);
]
Output:
[[1], [2], [3]] => Centroid: [2]
[[8, 2], [0, 0]] => Centroid: [4, 1]
[[5, 5, 0], [10, 10, 0]] => Centroid: [7.5, 7.5, 0]
[[1, 3.1, 6.5], [-2, -5, 3.4], [-7, -4, 9], [2, 0, 3]] => Centroid: [-1.5, -1.475, 5.475]
[[0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0]] => Centroid: [0, 0.25, 0.25, 0.25, 0.25]