Centro de Massa a partir de uma lista de coordenadas e suas massas

20

Aqui está um rápido desafio de segunda-feira de manhã ...

Escreva uma função ou programa no menor número de bytes que:

  • Toma como entrada uma lista de [x,y]coordenadas
  • Toma como entrada uma lista das [x,y]respectivas massas das coordenadas
  • Emite o centro de massa calculado na forma de [xBar,yBar].

Nota:

  • A entrada pode ser obtida de qualquer forma, desde que uma matriz seja usada.

O centro de massa pode ser calculado pela seguinte fórmula: Cálculos do Center of Mass

Em inglês simples...

  • Para encontrar xBar, multiplique cada massa por sua respectiva coordenada x, some a lista resultante e divida-a pela soma de todas as massas.
  • Para encontrar yBar, multiplique cada massa pela respectiva coordenada y, some a lista resultante e divida-a pela soma de todas as massas.

Exemplo de Trivial 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 teste:

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

Isso é código-golfe, então o menor número de bytes vence!

Mr Public
fonte
Como isso é apenas "calcular uma média ponderada de vetores", ficaria bastante surpreso se não o tivéssemos feito antes. (No momento, eu não consigo encontrar nada embora.)
Martin Ender
@ MartinBüttner Também parecia, e não consegui encontrar nenhum. Se esse é um truque, fique à vontade para fechá-lo.
Sr. Pública
A entrada pode ser obtida na outra ordem? Ou na forma [x,y,m],[x,y,m]...:?
FryAmTheEggman
@FryAmTheEggman Pergunta editada para entradas válidas.
Sr. Pública
@ MrPublic: Que tal [(x1,y1,m1), (x2,y2,m2)], por exemplo, uma lista de tuplas? Ou não importa se os argumentos são tuplas, listas ou matrizes? Que tal três listas / matrizes?
Zeta

Respostas:

21

MATL , 6 5 bytes

ys/Y*

O formato de entrada é um vetor de linha com as massas e, em seguida, uma matriz de duas colunas com as coordenadas (nas quais espaços ou vírgulas são opcionais).

  • Primeiro exemplo:

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

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

Experimente online!

Explicação

Vamos mdenotar o vetor de massas (primeira entrada) e ca 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
fonte
yé bastante útil !! +1
David
@David Yeah! Combinado com entrada implícita, ele faz um monte de coisas neste caso :-)
Luis Mendo
7

Mathematica, 10 bytes

#.#2/Tr@#&

Exemplo:

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

Out[1]= {7/5, 2}
alefalpha
fonte
1
Eu nunca usei Dot. Mas depois de ver seu uso acima!
DavidC
7

Mathcad, 19 "bytes"

insira a descrição da imagem aqui

  • Usa as tabelas do Mathcad para entrada de dados
  • Utiliza o produto escalar vetorial integrado do Mathcad para multiplicar ordenadas e massa de eixos
  • Usa o operador de somação interno do Mathcad para obter massa total

Como o Mathcad usa um "quadro branco" 2D e operadores especiais (por exemplo, operador de soma, operador integral) e salva em um formato XML, uma planilha real pode conter várias centenas (ou mais) de caracteres. Para os fins do Code Golf, consideramos uma "contagem de bytes" do Mathcad o número de caracteres ou operadores que o usuário deve inserir para criar a planilha.

A primeira versão (programa) do desafio ocupa 19 "bytes" usando esta definição e a versão da função ocupa 41 "bytes".

Stuart Bruff
fonte
3
Primeira vez que vi uma solução Matcad aqui. Muito agradável. +1.
rayryeng - Reinstala Monica
Obrigado, rayryeng. Provavelmente porque é um pouco desafiador fazer alguns dos "buracos" no "curso", uma vez que o Mathcad possui apenas funções básicas de string e não possui código-fonte legível por humanos e somente texto.
Stuart Bruff 31/03
6

MATLAB / Oitava, 18 16 bytes

Obrigado ao usuário beaker e Don Muesli por remover 2 bytes!

Dado que as coordenadas estão em uma N x 2matriz xonde a primeira coluna é a coordenada X e a segunda coluna é a coordenada Y, e as massas estão em uma 1 x Nmatriz y(ou um vetor de linha):

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

A explicação desse código é bastante direta. Esta é uma função anônima que recebe as duas entradas xe y. Realizamos a soma ponderada (a expressão numeradora de cada coordenada) em uma abordagem de álgebra linear usando a multiplicação de vetores matriciais. Ao pegar o vetor yde massas e multiplicá-lo pela matriz de coordenadas xpela multiplicação de vetores de matriz, você calcularia a soma ponderada de ambas as coordenadas individualmente, depois dividimos cada uma dessas coordenadas pela soma das massas, encontrando o centro desejado de massa retornada como um vetor de 1 x 2 linhas para cada coordenada, respectivamente.

Execuções de exemplo

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

Experimente online!

https://ideone.com/BzbQ3e

rayryeng - Restabelecer Monica
fonte
1
Você pode remover ;, e também 'escolhendo adequadamente formato de entrada ( xcomo vetor linha)
Luis Mendo
@DonMuesli Thanks :) Reduzida a contagem de bytes em 2. #
rayryeng - Restabelecer Monica 7/16/16
6

Gelatina, 6 bytes

S÷@×"S

ou

÷S$×"S

A entrada é feita por meio de dois argumentos de linha de comando, massa primeiro, coordenada segundo.

Experimente online!

Explicação

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

ou

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

Julia, 25 17 bytes

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

Perdeu a abordagem óbvia: / Ligue como f([3 1;0 0;1 4], [2 4 1]).

Sp3000
fonte
5

CJam, 14 bytes

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

Uma função sem nome com espera a lista de pares de coordenadas e a lista de massas na pilha (nessa ordem) e deixa o centro de massa em seu lugar.

Teste aqui.

Explicação

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

Perl 6, 36 33 30 bytes

{[Z+](@^a Z»*»@^b) X/sum @b}
Teclas de atalho
fonte
4

Sério, 16 bytes

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

Toma entrada como [x-coords]\n[y-coords]\n[masses]e sai comoxbar\nybar

Experimente online!

Explicação:

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

Haskell, 55 50 bytes

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

Isso define uma função binária f, usada da seguinte maneira:

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

Veja passar nos dois casos de teste.

Explicação

Haskell não é adequado para o processamento de listas multidimensionais, por isso estou pulando por aqui. A primeira linha define um alias curto para o zipWithqual precisamos duas vezes. Basicamente, fé uma função que pega a lista de pesos ae produz f a, uma função que pega a lista de posições e produz o centro de massa. f aé uma composição de três funções:

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

Aceita uma matriz de (x, y, massa) "triplica" e retorna uma "tupla".

Neil
fonte
Os parênteses são [x,y,m]necessários? iirc, eles não são necessários se houver apenas um argumento de entrada para a função de seta.
Patrick Roberts
@PatrickRoberts Sim, eles são necessários em todos os casos, exceto aquele trivial de exatamente um argumento padrão.
1111 Neil
3

R, 32 bytes 25

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

editar -7 bytes por mudar para álgebra matricial (obrigado @ Sp3000 resposta Julia)

passa uma matriz (matriz com 2 colunas, x, y) como coordenadas e vetor mde pesos, retorna uma matriz com as coordenadas necessárias

mnel
fonte
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 expandida
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 necessária
Array[Array]: [ [ mass1, mass2, ... ],
                [ xpos1, xpos2, ... ],
                [ ypos1, ypos2, ... ] ]
Retorna

Array: [ xbar, ybar ]


A p()função é um mapa básico, multiplicando cada [m]valor pelo valor [x]ou correspondente [y]. A c()função recebe Array[Array], apresenta as funções array_sume array_mappara o espaço e depois calculaΣmx/Σm e Σmy/Σm.

Pode ser possível transformar o próprio cálculo em uma função de espaço, verá.

ricdesi
fonte
2

Mathcad, 8 "bytes"

Não sei no que estava pensando na minha resposta anterior. Aqui está uma maneira mais curta de fazer uso adequado da multiplicação de matrizes. A variável p contém os dados - se a definição da variável for contabilizada no total, adicione mais 2 "bytes" (criação da tabela de entrada = 1 byte, nome da variável = 1 byte).

insira a descrição da imagem aqui

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

As operações de vetor nas listas são longas: /

Esta é uma função lambda anônima - dê um nome e chame como f([[0,2],[3,4],[0,1],[1,1]],[2,6,2,10]).

Sp3000
fonte
1

Python 3, 95 90 88 bytes

Solução

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]

graças a @Zgarb economizando 2 bytes


Uma solução recursiva por diversão (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
fonte
2
Eu acho que *([c]+[m])poderia ser reduzido para *[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])

ungolf it

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