Centro di messa da un elenco di coordinate e relative masse


20

Ecco una rapida sfida del lunedì mattina ...

Scrivi una funzione o un programma nel minor numero di byte che:

  • Accetta come input un elenco di [x,y]coordinate
  • Prende come input un elenco delle [x,y]rispettive masse delle coordinate
  • Emette il centro di massa calcolato sotto forma di [xBar,yBar].

Nota:

  • L'input può essere assunto in qualsiasi forma, purché venga utilizzato un array.

Il centro di massa può essere calcolato con la seguente formula: Calcoli del centro di massa

In parole povere ...

  • Per trovare xBar, moltiplicare ogni massa per la rispettiva coordinata x, sommare l'elenco risultante e dividerlo per la somma di tutte le masse.
  • Per trovare yBar, moltiplicare ciascuna massa per la rispettiva coordinata y, sommare l'elenco risultante e dividerlo per la somma di tutte le masse.

Trivial Python 2.7 esempio:

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]

Casi test:

> 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]

Questo è code-golf, quindi vince il minor numero di byte!


Dato che si tratta solo di "calcolare una media ponderata di vettori", sarei piuttosto sorpreso se non lo avessimo mai fatto prima. (Al momento non riesco a trovare nulla.)
Martin Ender

@ MartinBüttner Ho anche guardato, e non sono riuscito a trovarne. Se questo è un duplicato, sentiti libero di chiuderlo però.
Sig. Public

L'input può essere preso nell'altro ordine? O nella forma [x,y,m],[x,y,m]...:?
FryAmTheEggman

@FryAmTheEggman Domanda modificata per input validi.
Mr Public,

@MrPublic: che dire [(x1,y1,m1), (x2,y2,m2)], ad esempio, un elenco di tuple? O non importa se gli argomenti sono tuple, liste o matrici? Che dire di tre elenchi / matrici?
Zeta

Risposte:


21

MATL , 6 5 byte

ys/Y*

Il formato di input è un vettore di riga con le masse, quindi una matrice a due colonne con le coordinate (in cui gli spazi o le virgole sono opzionali).

  • Primo esempio:

    [2, 6, 2, 10]
    [0,2; 3,4; 0,1; 1,1]
    
  • Secondo esempio:

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

Provalo online!

Spiegazione

Lasciare mindicare il vettore di masse (primo ingresso) e cla matrice di coordinate (secondo ingresso).

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

yè abbastanza utile !! +1
David

@David Yeah! Combinato con input impliciti, fa molte cose in questo caso :-)
Luis Mendo

7

Mathematica, 10 byte

#.#2/Tr@#&

Esempio:

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

Out[1]= {7/5, 2}

1
Non ho mai usato Dot. Ma dopo aver visto il tuo utilizzo sopra!
DavidC

7

Mathcad, 19 "byte"

enter image description here

  • Utilizza le tabelle di Mathcad per l'immissione dei dati
  • Utilizza il prodotto scalare vettoriale incorporato di Mathcad per moltiplicare l'ordinata e la massa degli assi
  • Utilizza l'operatore di somma incorporato di Mathcad per la massa totale

Poiché Mathcad utilizza una "lavagna" 2D e operatori speciali (ad es. Operatore di somma, operatore integrale) e salva in un formato XML, un foglio di lavoro reale può contenere diverse centinaia (o più) caratteri. Ai fini di Code Golf, ho considerato un "conteggio byte" di Mathcad come il numero di caratteri o operatori che l'utente deve inserire per creare il foglio di lavoro.

La prima versione (del programma) della sfida richiede 19 "byte" usando questa definizione e la versione della funzione prende 41 "byte".


3
La prima volta che ho mai visto una soluzione Matcad qui. Molto bella. +1.
rayryeng - Ripristina Monica

Grazie, Rayryeng. Probabilmente è perché è un po 'una sfida fare alcuni dei "buchi" sul "percorso" dato che Mathcad ha solo funzioni di stringa di base e non ha un codice sorgente leggibile dall'uomo, solo testo.
Stuart Bruff

6

MATLAB / Octave, 18 16 byte

Grazie all'utente becher e Don Muesli per la rimozione di 2 byte!

Dato che le coordinate sono in una N x 2matrice in xcui la prima colonna è la coordinata X e la seconda colonna è la coordinata Y, e le masse sono in una 1 x Nmatrice y(o un vettore di riga):

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

La spiegazione di questo codice è abbastanza semplice. Questa è una funzione anonima che accetta i due input xe y. Eseguiamo la somma ponderata (l'espressione numeratrice di ciascuna coordinata) in un approccio di algebra lineare usando la moltiplicazione matrice-vettore. Prendendo il vettore ydi masse e moltiplicandolo con la matrice di coordinate xper moltiplicazione matrice-vettore, calcolereste individualmente la somma ponderata di entrambe le coordinate, quindi dividiamo ciascuna di queste coordinate per la somma delle masse, trovando così il centro desiderato di massa restituita come vettore di riga 1 x 2 per ciascuna coordinata rispettivamente.

L'esempio funziona

>> 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

Provalo online!

https://ideone.com/BzbQ3e


1
È possibile rimuovere ;e anche 'scegliendo correttamente il formato di input ( xcome vettore riga)
Luis Mendo

@DonMuesli Grazie :) Ridotto il conteggio dei byte di 2.
rayryeng - Ripristina Monica

6

Gelatina, 6 byte

S÷@×"S

o

÷S$×"S

L'input avviene tramite due argomenti della riga di comando, prima le masse, le coordinate secondo.

Provalo online!

Spiegazione

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

o

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

6

Julia, 25 17 byte

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

Perso l'approccio ovvio: / Chiama come f([3 1;0 0;1 4], [2 4 1]).


5

CJam, 14 byte

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

Una funzione senza nome con si aspetta l'elenco delle coppie di coordinate e l'elenco delle masse in pila (in quell'ordine) e lascia il centro di massa al loro posto.

Provalo qui.

Spiegazione

_    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.


4

Scherzi a parte, 16 byte

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

Accetta input as [x-coords]\n[y-coords]\n[masses]e output asxbar\nybar

Provalo online!

Spiegazione:

╩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

3

Haskell, 55 50 byte

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

Questo definisce una funzione binaria f, utilizzata come segue:

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

Guardalo passare entrambi i casi di test.

Spiegazione

Haskell non è adatto per l'elaborazione di elenchi multidimensionali, quindi sto saltando attraverso alcuni cerchi qui. La prima riga definisce un breve alias zipWith, di cui abbiamo bisogno due volte. Fondamentalmente, fè una funzione che prende l'elenco dei pesi ae produce f a, una funzione che prende l'elenco delle posizioni e produce il centro di massa. f aè una composizione di tre funzioni:

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

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]

Accetta una matrice di (x, y, mass) "triple" e restituisce una "tupla".


Le parentesi sono [x,y,m]necessarie? iirc, non sono necessari se esiste solo un argomento di input per la funzione freccia.
Patrick Roberts,

@PatrickRoberts Sì, sono necessari in tutti i casi tranne quello banale di esattamente un argomento standard.
Neil,

3

R, 32 25 byte

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

modifica -7 byte passando all'algebra matriciale (grazie alla risposta @ Sp3000 Julia)

passa una matrice (matrice con 2 colonne, x, y) come coordinate e vettore mdei pesi, restituisce una matrice con le coordinate richieste


2

PHP, 142 byte

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)];}
Vista esplosa
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) ];
}
Input richiesto
Array[Array]: [ [ mass1, mass2, ... ],
                [ xpos1, xpos2, ... ],
                [ ypos1, ypos2, ... ] ]
Ritorno

Array: [ xbar, ybar ]


La p()funzione è una mappa di base, moltiplicando ogni [m]valore con il corrispondente [x]o [y]valore. La c()funzione accetta Array[Array], presenta le funzioni array_sume array_mapper lo spazio, quindi calcola Σmx/Σme Σmy/Σm.

Potrebbe essere possibile trasformare il calcolo stesso in una funzione per lo spazio, vedrà.


2

Mathcad, 8 "byte"

Non so a cosa non stavo pensando nella mia risposta precedente. Ecco un modo più breve di utilizzare correttamente la moltiplicazione di matrici. La variabile p contiene i dati - se si imposta la variabile conta per il totale, quindi aggiungere altri 2 "byte" (creazione della tabella di input = 1 byte, nome della variabile = 1 byte).

inserisci qui la descrizione dell'immagine


1

Python 3, 63 byte

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

Le operazioni vettoriali sugli elenchi sono lunghe: /

Questa è una funzione lambda anonima: dagli un nome e chiama come f([[0,2],[3,4],[0,1],[1,1]],[2,6,2,10]).


1

Python 3, 95 90 88 byte

Soluzione

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

risultati

>>> 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]

grazie a @Zgarb risparmiando 2 byte


Una soluzione ricorsiva per divertimento (95 byte)

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]

risultati

>>> 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]

2
Penso che *([c]+[m])potrebbe essere abbreviato *[c,m].
Zgarb

0

Assioma, 158 byte

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 esso

-- 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]

risultati

(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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.