Massenschwerpunkt aus einer Liste von Koordinaten und deren Massen

20

Hier ist eine kurze Herausforderung am Montagmorgen ...

Schreiben Sie eine Funktion oder ein Programm in der geringsten Anzahl von Bytes, die:

  • Nimmt als Eingabe eine Liste von [x,y]Koordinaten
  • Nimmt als Eingabe eine Liste der [x,y]jeweiligen Massen der Koordinaten
  • Gibt den berechneten Schwerpunkt in Form von aus [xBar,yBar].

Hinweis:

  • Die Eingabe kann in beliebiger Form erfolgen, solange ein Array verwendet wird.

Der Schwerpunkt kann nach folgender Formel berechnet werden: Massenschwerpunktberechnungen

In reinem Englisch...

  • Um zu finden xBar, multiplizieren Sie jede Masse mit ihrer jeweiligen x-Koordinate, addieren Sie die resultierende Liste und dividieren Sie sie durch die Summe aller Massen.
  • Um zu finden yBar, multiplizieren Sie jede Masse mit ihrer jeweiligen y-Koordinate, addieren Sie die resultierende Liste und dividieren Sie sie durch die Summe aller Massen.

Trivial Python 2.7 Beispiel:

def center(coord, mass):
    sumMass = float(reduce(lambda a, b: a+b, mass))
    momentX = reduce(lambda m, x: m+x, (a*b for a, b in zip(mass, zip(*coord)[0])))
    momentY = reduce(lambda m, y: m+y, (a*b for a, b in zip(mass, zip(*coord)[1])))
    xBar = momentX / sumMass
    yBar = momentY / sumMass
    return [xBar, yBar]

Testfälle:

> center([[0, 2], [3, 4], [0, 1], [1, 1]], [2, 6, 2, 10])
[1.4, 2.0]

> center([[3, 1], [0, 0], [1, 4]], [2, 4, 1])
[1.0, 0.8571428571428571]

Das ist Code-Golf, also gewinnt die geringste Anzahl von Bytes!

Herr Public
quelle
Da dies nur "Berechnen eines gewichteten Durchschnitts von Vektoren" ist, wäre ich ziemlich überrascht, wenn wir dies noch nicht getan hätten. (Im Moment kann ich jedoch nichts finden.)
Martin Ender
@ MartinBüttner Ich habe auch gesucht und konnte keine finden. Wenn dies ein Betrug ist, können Sie ihn trotzdem schließen.
Mr Public
Kann die Eingabe in der anderen Reihenfolge erfolgen? Oder in der Form [x,y,m],[x,y,m]...:?
FryAmTheEggman
@FryAmTheEggman Frage für gültige Eingaben bearbeitet.
Mr Public
@MrPublic: Wie wäre es [(x1,y1,m1), (x2,y2,m2)]zB mit einer Liste von Tupeln? Oder spielt es keine Rolle, ob es sich bei den Argumenten um Tupel, Listen oder Arrays handelt? Was ist mit drei Listen / Arrays?
Zeta

Antworten:

21

MATL , 6 5 Bytes

ys/Y*

Das Eingabeformat ist ein Zeilenvektor mit den Massen, dann eine zweispaltige Matrix mit den Koordinaten (in denen Leerzeichen oder Kommas optional sind).

  • Erstes Beispiel:

    [2, 6, 2, 10]
    [0,2; 3,4; 0,1; 1,1]
    
  • Zweites Beispiel:

    [2, 4, 1]
    [3,1; 0,0; 1,4]
    

Probieren Sie es online!

Erläuterung

mBezeichnen wir den Massenvektor (erste Eingabe) und cdie Koordinatenmatrix (zweite Eingabe).

y     % implicitly take two inputs. Duplicate the first.
      % (Stack contains, bottom to top: m, c, m)
s     % sum of m.
      % (Stack: m, c, sum-of-m)
/     % divide.
      % (Stack: m, c-divided-by-sum-of-m)
Y*    % matrix multiplication.
      % (Stack: final result)
      % implicitly display
Luis Mendo
quelle
yist ziemlich nützlich !! +1
David
@ David Yeah! Kombiniert mit impliziten Eingaben macht es in diesem Fall viele Dinge :-)
Luis Mendo
7

Mathematica, 10 Bytes

#.#2/Tr@#&

Beispiel:

In[1]:= #.#2/Tr@#&[{2,6,2,10},{{0,2},{3,4},{0,1},{1,1}}]

Out[1]= {7/5, 2}
Alephalpha
quelle
1
Ich habe es nie benutzt Dot. Aber ich werde nach Ihrer Verwendung oben sehen!
DavidC
7

Mathcad, 19 "Bytes"

Bildbeschreibung hier eingeben

  • Verwendet Mathcads Tabellen für die Dateneingabe
  • Verwendet das in Mathcad integrierte Vektorskalarprodukt zum Multiplizieren von Achsenordinate und Masse
  • Verwendet den in Mathcad integrierten Summationsoperator für die Gesamtmasse

Da Mathcad ein 2D-Whiteboard und spezielle Operatoren (z. B. Summationsoperator, Integraloperator) verwendet und in einem XML-Format speichert, kann ein tatsächliches Arbeitsblatt mehrere hundert (oder mehr) Zeichen enthalten. Für die Zwecke von Code Golf habe ich die Anzahl der Zeichen oder Operatoren, die der Benutzer eingeben muss, um das Arbeitsblatt zu erstellen, als Mathcad-Bytezahl definiert.

Die erste (Programm-) Version der Challenge benötigt nach dieser Definition 19 "Bytes" und die Funktionsversion 41 "Bytes".

Stuart Bruff
quelle
3
Zum ersten Mal habe ich hier eine Matcad-Lösung gesehen. Sehr schön. +1.
Rayryeng - Wiedereinsetzung von Monica
Vielen Dank, Rayryeng. Dies liegt wahrscheinlich daran, dass es eine Herausforderung ist, einige der "Löcher" auf dem "Platz" zu bohren, da Mathcad nur grundlegende Zeichenfolgenfunktionen und keinen für Menschen lesbaren Quellcode nur für Text enthält.
Stuart Bruff
6

MATLAB / Octave, 18 bis 16 Bytes

Vielen Dank an User Becher und Don Müsli für das Entfernen von 2 Bytes!

Vorausgesetzt, die Koordinaten befinden sich in einer N x 2Matrix, xin der die erste Spalte die X-Koordinate und die zweite Spalte die Y-Koordinate ist, und die Massen befinden sich in einer 1 x NMatrix y(oder einem Zeilenvektor):

@(x,y)y*x/sum(y)

Die Erklärung dieses Codes ist ziemlich einfach. Dies ist eine anonyme Funktion, die die beiden Eingaben xund aufnimmt y. Wir führen die gewichtete Summation (der Zählerausdruck jeder Koordinate) in einem linearen Algebra-Ansatz unter Verwendung der Matrix-Vektor-Multiplikation durch. Indem Sie den yMassenvektor nehmen und diesen mit der Koordinatenmatrix xdurch Matrix-Vektor-Multiplikation multiplizieren, würden Sie die gewichtete Summe beider Koordinaten einzeln berechnen, dann dividieren wir jede dieser Koordinaten durch die Summe der Massen und finden so den gewünschten Mittelpunkt von Masse, die als 1 x 2 Zeilenvektor für jede Koordinate zurückgegeben wird.

Beispiel läuft

>> A=@(x,y)y*x/sum(y)

A = 

    @(x,y)y*x/sum(y)

>> x = [0 2; 3 4; 0 1; 1 1];
>> y = [2 6 2 10];
>> A(x,y)

ans =

    1.4000    2.0000

>> x = [3 1; 0 0; 1 4];
>> y = [2 4 1];
>> A(x,y)

ans =

    1.0000    0.8571

Probieren Sie es online!

https://ideone.com/BzbQ3e

rayryeng - Setzen Sie Monica wieder ein
quelle
1
Sie können entfernen ;, und auch 'durch die richtige Auswahl des Eingabeformats ( xals Zeilenvektor)
Luis Mendo
@ DonMuesli Danke :) Reduziert die
Byteanzahl
6

Gelee, 6 Bytes

S÷@×"S

oder

÷S$×"S

Die Eingabe erfolgt über zwei Befehlszeilenargumente: Masse zuerst, Koordinate zweitens.

Probieren Sie es online!

Erläuterung

S       Sum the masses.
   x"   Multiply each vector by the corresponding mass.
 ÷@     Divide the results by the sum of masses.
     S  Sum the vectors.

oder

÷S$     Divide the masses by their sum.
   ×"   Multiply each vector by the corresponding normalised mass.
     S  Sum the vectors.
Martin Ender
quelle
6

Julia, 25 17 Bytes

f(c,m)=m*c/sum(m)

Verpasste den offensichtlichen Ansatz: / Call like f([3 1;0 0;1 4], [2 4 1]).

Sp3000
quelle
5

CJam, 14 Bytes

{_:+df/.f*:.+}

Eine unbenannte Funktion mit erwartet die Liste der Koordinatenpaare und die Liste der Massen auf dem Stapel (in dieser Reihenfolge) und belässt den Massenmittelpunkt an ihrer Stelle.

Teste es hier.

Erläuterung

_    e# Duplicate list of masses.
:+d  e# Get sum, convert to double.
f/   e# Divide each mass by the sum, normalising the list of masses.
.f*  e# Multiply each component of each vector by the corresponding weight.
:.+  e# Element-wise sum of all weighted vectors.
Martin Ender
quelle
5

Perl 6, 36 33 30 Bytes

{[Z+](@^a Z»*»@^b) X/sum @b}
Hotkeys
quelle
4

Im Ernst, 16 Bytes

╩2└Σ;╛2└*/@╜2└*/

Nimmt Eingaben als [x-coords]\n[y-coords]\n[masses]und Ausgaben alsxbar\nybar

Probieren Sie es online!

Erläuterung:

╩2└Σ;╛2└*/@╜2└*/
╩                 push each line of input into its own numbered register
 2└Σ;             push 2 copies of the sum of the masses
     ╛2└*/        push masses and y-coords, dot product, divide by sum of masses
          @       swap
           ╜2└*/  push masses and x-coords, dot product, divide by sum of masses
Mego
quelle
3

Haskell, 55 50 Bytes

z=zipWith
f a=map(/sum a).foldr1(z(+)).z(map.(*))a

Dies definiert eine Binärfunktion f, die wie folgt verwendet wird:

> f [1,2] [[1,2],[3,4]]
[2.3333333333333335,3.333333333333333]

Sehen Sie, wie es beide Testfälle besteht.

Erläuterung

Haskell ist nicht gut für die Verarbeitung mehrdimensionaler Listen geeignet, daher gehe ich hier einige Rahmen durch. Die erste Zeile definiert einen kurzen Alias ​​für zipWithden wir zweimal benötigen. Grundsätzlich fist dies eine Funktion, die die Liste der Gewichte aufnimmt aund erzeugt f a, eine Funktion, die die Liste der Positionen aufnimmt und den Massenmittelpunkt erzeugt. f abesteht aus drei Funktionen:

z(map.(*))a      -- First sub-function:
z         a      --   Zip the list of positions with the mass list a
  map.(*)        --   using the function map.(*), which takes a mass m
                 --   and maps (*m) over the corresponding position vector
foldr1(z(+))     -- Second sub-function:
foldr1           --   Fold (reduce) the list of mass-times-position vectors
       z(+)      --   using element-wise addition
map(/sum a)      -- Third sub-function:
map              --   Map over both coordinates:
   (/sum a)      --     Divide by the sum of all masses
Zgarb
quelle
3

JavaScript (ES6), 60 Byte

a=>a.map(([x,y,m])=>{s+=m;t+=x*m;u+=y*m},s=t=u=0)&&[t/s,u/s]

Akzeptiert ein Array von (x, y, mass) "Triple" und gibt ein "Tupel" zurück.

Neil
quelle
Sind die Klammern um [x,y,m]notwendig? Sie sind nicht erforderlich, wenn die Pfeilfunktion nur ein Eingabeargument enthält.
Patrick Roberts
@PatrickRoberts Ja, sie sind in allen Fällen erforderlich, mit Ausnahme eines einfachen von genau einem Standardargument.
Neil
3

R 32 25 Bytes

function(a,m)m%*%a/sum(m)

-7 Bytes durch Umschalten auf Matrixalgebra bearbeiten (danke @ Sp3000 Julia Antwort)

Übergeben Sie ein Array (Matrix mit 2 Spalten, x, y) als Koordinaten und mGewichtungsvektor, und geben Sie ein Array mit den erforderlichen Koordinaten zurück

mnel
quelle
2

PHP, 142 Bytes

function p($q,$d){return$q*$d;}function c($f){$s=array_sum;$m=array_map;$e=$f[0];return[$s($m(p,$e,$f[1]))/$s($e),$s($m(p,$e,$f[2]))/$s($e)];}
Explosionszeichnung
function p($q, $d) {
  return $q * $d;
}

function c($f) {
  $s = array_sum;
  $m = array_map;
  $e = $f[0];
  return [ $s($m(p,$e,$f[1])) / $s($e),
           $s($m(p,$e,$f[2])) / $s($e) ];
}
Erforderliche Eingabe
Array[Array]: [ [ mass1, mass2, ... ],
                [ xpos1, xpos2, ... ],
                [ ypos1, ypos2, ... ] ]
Rückkehr

Array: [ xbar, ybar ]


Die p()Funktion ist eine Basiskarte, [m]bei der jeder Wert mit dem entsprechenden Wert [x]oder [y]multipliziert wird. Die c()Funktion in der nimmt Array[Array], stellt die array_sumund array_mapfür die Raumfunktionen, dann berechnet Σmx/Σmund Σmy/Σm.

Könnte es möglich sein, die Berechnung selbst in eine Funktion für den Raum zu verwandeln, wird sich zeigen.

Ricdesi
quelle
2

Mathcad, 8 "Bytes"

Ich weiß nicht, woran ich in meiner vorherigen Antwort nicht gedacht habe. Hier ist ein kürzerer Weg, um die Matrixmultiplikation richtig einzusetzen. Die Variable p enthält die Daten. Wenn Sie die Anzahl der Variablen auf die Gesamtsumme setzen, addieren Sie weitere 2 "Bytes" (Erstellung der Eingabetabelle = 1 Byte, Variablenname = 1 Byte).

Bildbeschreibung hier eingeben

Stuart Bruff
quelle
1

Python 3, 63 Bytes

lambda a,b:[sum(x*y/sum(b)for x,y in zip(L,b))for L in zip(*a)]

Vektoroperationen auf Listen sind lang: /

Dies ist eine anonyme Lambda-Funktion. Geben Sie einen Namen und rufen Sie wie folgt auf f([[0,2],[3,4],[0,1],[1,1]],[2,6,2,10]).

Sp3000
quelle
1

Python 3, 95 90 88 Bytes

Lösung

lambda c,m:list(map(sum,zip(*[[i[0]*j/sum(m),i[1]*j/sum(m)]for i,j in zip(*([c,m]))])))

Ergebnisse

>>> f([[0,2],[3,4],[0,1],[1,1]],[2,6,2,10])
[1.3999999999999999, 2.0]
>>> f([[3,1],[0,0],[1,4]],[2,4,1])
[1.0, 0.8571428571428571]

dank @Zgarb sparen 2 Bytes


Eine rekursive Lösung zum Spaß (95 Bytes)

f=lambda c,m,x=0,y=0,s=0:f(c[1:],m[1:],x+c[0][0]*m[0],y+c[0][1]*m[0],s+m[0])if c else[x/s,y/s]

Ergebnisse

>>> f([[0,2],[3,4],[0,1],[1,1]],[2,6,2,10])
[1.4, 2.0]
>>> f([[3,1],[0,0],[1,4]],[2,4,1])
[1.0, 0.8571428571428571]
Erwan
quelle
2
Ich denke, *([c]+[m])könnte zu verkürzt werden *[c,m].
Zgarb
0

Axiom, 158 Bytes

c(a:List List Float):List Float==(x:=y:=m:=0.;for i in 1..#a repeat(~index?(3,a.i)=>return[];x:=x+a.i.3*a.i.1;y:=y+a.i.3*a.i.2;m:=m+a.i.3);m=0.=>[];[x/m,y/m])

ungolf es

-- Input List of Coordinate and masses as [[xi,yi,mi]]
-- Return center of mass for the list a as [x,y] Float coordinates
-- or [] if some error occur [for example masses are all 0]
cc(a:List List Float):List Float==
    x:=y:=m:=0.
    for i in 1..#a repeat
         ~index?(3,a.i)=>return []
         x:=x+a.i.3*a.i.1
         y:=y+a.i.3*a.i.2
         m:=m+a.i.3
    m=0.=>return []
    return[x/m,y/m]

Ergebnisse

(21) -> c([[0,2,2],[3,4,6],[0,1,2],[1,1,10]])
   (21)  [1.4,2.0]
                                                         Type: List Float
(22) -> c([[3,1,2],[0,0,4],[1,4,1]])
   (22)  [1.0,0.8571428571 4285714286]
                                                         Type: List Float
RosLuP
quelle