Centro de masa de una lista de coordenadas y sus masas.

20

Aquí hay un desafío rápido el lunes por la mañana ...

Escriba una función o programa en el menor número de bytes que:

  • Toma como entrada una lista de [x,y]coordenadas
  • Toma como entrada una lista de las [x,y]masas respectivas de las coordenadas.
  • Emite el centro de masa calculado en forma de [xBar,yBar].

Nota:

  • La entrada se puede tomar de cualquier forma, siempre que se use una matriz.

El centro de masa se puede calcular mediante la siguiente fórmula: Cálculos del centro de masa

En inglés simple...

  • Para encontrar xBar, multiplique cada masa por su respectiva coordenada x, sume la lista resultante y divídala por la suma de todas las masas.
  • Para encontrar yBar, multiplique cada masa por su respectiva coordenada y, sume la lista resultante y divídala por la suma de todas las masas.

Ejemplo trivial de Python 2.7:

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]

Casos de prueba:

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

Este es el código de golf, por lo que gana el menor número de bytes.

Señor público
fuente
Dado que esto es solo "calcular un promedio ponderado de vectores", me sorprendería bastante si no lo hemos hecho antes. (Por el momento, no puedo encontrar nada sin embargo.)
Martin Ender
@ MartinBüttner También miré, y no pude encontrar ninguno. Sin embargo, si esto es un engaño, no dude en cerrarlo.
Mr Public
¿Se puede tomar la entrada en el otro orden? O en la forma [x,y,m],[x,y,m]...:?
FryAmTheEggman
@FryAmTheEggman Pregunta editada para entradas válidas.
Mr Public
@MrPublic: ¿Qué pasa [(x1,y1,m1), (x2,y2,m2)], por ejemplo, una lista de tuplas? ¿O no importa si los argumentos son tuplas, listas o matrices? ¿Qué pasa con tres listas / matrices?
Zeta

Respuestas:

21

MATL , 6 5 bytes

ys/Y*

El formato de entrada es un vector de fila con las masas, luego una matriz de dos columnas con las coordenadas (en las que los espacios o comas son opcionales).

  • Primer ejemplo:

    [2, 6, 2, 10]
    [0,2; 3,4; 0,1; 1,1]
    
  • Segundo ejemplo

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

Pruébalo en línea!

Explicación

Deje mdenotar el vector de masas (primera entrada) y cla matriz de coordenadas (segunda entrada).

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
fuente
yes bastante util !! +1
David
@David Yeah! Combinado con la entrada implícita, hace muchas cosas en este caso :-)
Luis Mendo
7

Mathematica, 10 bytes

#.#2/Tr@#&

Ejemplo:

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

Out[1]= {7/5, 2}
alephalpha
fuente
1
Yo nunca lo usé Dot. ¡Pero lo haré después de ver tu uso arriba!
DavidC
7

Mathcad, 19 "bytes"

ingrese la descripción de la imagen aquí

  • Utiliza las tablas de Mathcad para la entrada de datos.
  • Utiliza el producto escalar vectorial incorporado de Mathcad para multiplicar la ordenada y la masa del eje
  • Utiliza el operador de suma incorporado de Mathcad para la masa total

Como Mathcad utiliza una "pizarra" 2D y operadores especiales (por ejemplo, operador de suma, operador integral) y guarda en un formato XML, una hoja de trabajo real puede contener varios cientos (o más) caracteres. Para los propósitos de Code Golf, he tomado un "conteo de bytes" de Mathcad para que sea el número de caracteres u operadores que el usuario debe ingresar para crear la hoja de trabajo.

La primera versión (programa) del desafío toma 19 "bytes" usando esta definición y la versión de la función toma 41 "bytes".

Stuart Bruff
fuente
3
La primera vez que he visto una solución de Matcad aquí. Muy agradable. +1.
rayryeng - Restablecer Monica
Gracias Rayryeng. Probablemente se deba a que es un poco difícil hacer algunos de los "agujeros" en el "curso" dado que Mathcad solo tiene funciones de cadena básicas y no tiene un código fuente de solo texto legible por humanos.
Stuart Bruff
6

MATLAB / Octave, 18 16 bytes

¡Gracias al usuario beaker y Don Muesli por eliminar 2 bytes!

Dado que las coordenadas están en una N x 2matriz xdonde la primera columna es la coordenada X y la segunda columna es la coordenada Y, y las masas están en una 1 x Nmatriz y(o un vector de fila):

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

La explicación de este código es bastante sencilla. Esta es una función anónima que toma las dos entradas xy y. Realizamos la suma ponderada (la expresión del numerador de cada coordenada) en un enfoque de álgebra lineal usando la multiplicación de matriz-vector. Al tomar el vector yde masas y multiplicar esto con la matriz de coordenadas xpor la multiplicación de matriz-vector, calcularía la suma ponderada de ambas coordenadas individualmente, luego dividiremos cada una de estas coordenadas por la suma de las masas, encontrando así el centro deseado de masa devuelta como un vector de fila de 1 x 2 para cada coordenada, respectivamente.

Ejecuciones de ejemplo

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

Pruébalo en línea!

https://ideone.com/BzbQ3e

rayryeng - Restablece a Monica
fuente
1
Puede eliminar ;, y también 'eligiendo correctamente el formato de entrada ( xcomo vector de fila)
Luis Mendo
@DonMuesli Gracias :) Redujo el conteo de bytes en 2.
rayryeng - Restablece Monica
6

Jalea, 6 bytes

S÷@×"S

o

÷S$×"S

La entrada es a través de dos argumentos de línea de comando, masas primero, coordenadas segundo.

Pruébalo en línea!

Explicación

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.
Martin Ender
fuente
6

Julia, 25 17 bytes

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

Perdí el enfoque obvio: / Llamada como f([3 1;0 0;1 4], [2 4 1]).

Sp3000
fuente
5

CJam, 14 bytes

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

Una función sin nombre espera la lista de pares de coordenadas y la lista de masas en la pila (en ese orden) y deja el centro de masa en su lugar.

Pruébalo aquí.

Explicación

_    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
fuente
5

Perl 6, 36 33 30 bytes

{[Z+](@^a Z»*»@^b) X/sum @b}
Teclas de acceso rápido
fuente
4

En serio, 16 bytes

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

Toma entradas como [x-coords]\n[y-coords]\n[masses]y salidas comoxbar\nybar

Pruébalo en línea!

Explicación:

╩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
fuente
3

Haskell, 55 50 bytes

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

Esto define una función binaria f, utilizada de la siguiente manera:

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

Véalo pasar ambos casos de prueba.

Explicación

Haskell no es muy adecuado para procesar listas multidimensionales, por lo que estoy saltando algunos aros aquí. La primera línea define un alias corto para zipWith, que necesitamos dos veces. Básicamente, fes una función que toma la lista de pesos ay produce f a, una función que toma la lista de posiciones y produce el centro de masa. f aes una composición de tres funciones:

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

JavaScript (ES6), 60 bytes

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

Acepta una matriz de (x, y, masa) "triples" y devuelve una "tupla".

Neil
fuente
¿Son [x,y,m]necesarios los paréntesis ? iirc, no son necesarios si solo hay un argumento de entrada para la función de flecha.
Patrick Roberts
@PatrickRoberts Sí, son necesarios en todos los casos, excepto aquel trivial de exactamente un argumento estándar.
Neil
3

R, 32 25 bytes

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

editar -7 bytes cambiando a álgebra matricial (gracias @ Sp3000 respuesta de Julia)

pasar una matriz (matriz con 2 columnas, x, y) como coordenadas y vector mde pesos, devuelve una matriz con las coordenadas requeridas

mnel
fuente
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)];}
Vista en despiece ordenado
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) ];
}
Entrada requerida
Array[Array]: [ [ mass1, mass2, ... ],
                [ xpos1, xpos2, ... ],
                [ ypos1, ypos2, ... ] ]
Regreso

Array: [ xbar, ybar ]


La p()función es un mapa básico, multiplicando cada [m]valor con el correspondiente [x]o [y]valor. La c()función toma Array[Array], presenta las funciones array_sumy array_mappara el espacio, luego calcula Σmx/Σmy Σmy/Σm.

Podría ser posible convertir el cálculo en sí mismo en una función para el espacio, verá.

ricdesi
fuente
2

Mathcad, 8 "bytes"

No sé en qué no estaba pensando en mi respuesta anterior. Aquí hay una forma más corta de hacer un uso adecuado de la multiplicación de matrices. La variable p contiene los datos: si la configuración de la variable cuenta hacia el total, agregue otros 2 "bytes" (creación de la tabla de entrada = 1 byte, nombre de la variable = 1 byte).

ingrese la descripción de la imagen aquí

Stuart Bruff
fuente
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)]

Las operaciones vectoriales en las listas son largas: /

Esta es una función lambda anónima: asígnele un nombre y llame como f([[0,2],[3,4],[0,1],[1,1]],[2,6,2,10]).

Sp3000
fuente
1

Python 3, 95 90 88 bytes

Solución

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

Resultados

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

gracias a @Zgarb ahorrando 2 bytes


Una solución recursiva para la diversión (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]

Resultados

>>> 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
fuente
2
Creo que *([c]+[m])podría acortarse *[c,m].
Zgarb
0

Axioma, 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])

deshacerse de él

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

resultados

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