Centre de masse à partir d'une liste de coordonnées et de leurs masses

20

Voici un petit défi du lundi matin ...

Écrivez une fonction ou un programme dans le moins d'octets qui:

  • Prend en entrée une liste de [x,y]coordonnées
  • Prend en entrée une liste des [x,y]masses respectives des coordonnées
  • Sort le centre de masse calculé sous la forme de [xBar,yBar].

Remarque:

  • L'entrée peut être prise sous n'importe quelle forme, tant qu'un tableau est utilisé.

Le centre de masse peut être calculé par la formule suivante: Calculs du centre de masse

En anglais simple ...

  • Pour trouver xBar, multipliez chaque masse par sa coordonnée x respective, additionnez la liste résultante et divisez-la par la somme de toutes les masses.
  • Pour trouver yBar, multipliez chaque masse par sa coordonnée y respective, additionnez la liste résultante et divisez-la par la somme de toutes les masses.

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

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

Il s'agit de code-golf, donc le moins d'octets gagne!

Mr Public
la source
Comme il s'agit simplement de "calculer une moyenne pondérée de vecteurs", je serais très surpris si nous ne l'avions pas fait auparavant. (Pour le moment, je ne trouve rien.)
Martin Ender
@ MartinBüttner J'ai aussi regardé et je n'en ai pas trouvé. S'il s'agit d'un dupe, n'hésitez pas à le refermer.
Mr Public
L'entrée peut-elle être prise dans l'autre ordre? Ou sous la forme [x,y,m],[x,y,m]...:?
FryAmTheEggman
@FryAmTheEggman Question modifiée pour des entrées valides.
M. Public
@MrPublic: Qu'en est-il par [(x1,y1,m1), (x2,y2,m2)]exemple d'une liste de tuples? Ou importe peu que les arguments soient des tuples, des listes ou des tableaux? Qu'en est-il de trois listes / tableaux?
Zeta

Réponses:

21

MATL , 6 5 octets

ys/Y*

Le format d'entrée est un vecteur ligne avec les masses, puis une matrice à deux colonnes avec les coordonnées (dans lesquelles les espaces ou virgules sont facultatifs).

  • Premier exemple:

    [2, 6, 2, 10]
    [0,2; 3,4; 0,1; 1,1]
    
  • Deuxième exemple:

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

Essayez-le en ligne!

Explication

Soit mle vecteur des masses (première entrée) et cla matrice des coordonnées (deuxième entrée).

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
la source
yest assez utile !! +1
David
@David Ouais! Combiné avec une entrée implicite, il fait beaucoup de choses dans ce cas :-)
Luis Mendo
7

Mathematica, 10 octets

#.#2/Tr@#&

Exemple:

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

Out[1]= {7/5, 2}
alephalpha
la source
1
Je n'ai jamais utilisé Dot. Mais je le ferai après avoir vu votre utilisation ci-dessus!
DavidC
7

Mathcad, 19 "octets"

entrez la description de l'image ici

  • Utilise les tables de Mathcad pour la saisie de données
  • Utilise le produit scalaire vectoriel intégré de Mathcad pour multiplier les ordonnées et la masse des axes
  • Utilise l'opérateur de sommation intégré de Mathcad pour la masse totale

Comme Mathcad utilise un "tableau blanc" 2D et des opérateurs spéciaux (par exemple, opérateur de sommation, opérateur intégral) et enregistre au format XML, une feuille de calcul réelle peut contenir plusieurs centaines (ou plus) de caractères. Aux fins de Code Golf, j'ai pris un "nombre d'octets" Mathcad comme étant le nombre de caractères ou d'opérateurs que l'utilisateur doit entrer pour créer la feuille de calcul.

La première version (du programme) du défi prend 19 "octets" en utilisant cette définition et la version de la fonction prend 41 "octets".

Stuart Bruff
la source
3
C'est la première fois que je vois une solution Matcad ici. Très agréable. +1.
rayryeng
Merci, rayryeng. C'est probablement parce que c'est un peu difficile de faire certains des «trous» du «cours» étant donné que Mathcad n'a que des fonctions de chaîne de base et n'a pas de code source lisible par l'homme et uniquement en texte.
Stuart Bruff
6

MATLAB / Octave, 18 16 octets

Merci à l'utilisateur bécher et Don Muesli pour avoir supprimé 2 octets!

Étant donné que les coordonnées sont dans une N x 2matrice xoù la première colonne est la coordonnée X et la deuxième colonne est la coordonnée Y, et les masses sont dans une 1 x Nmatrice y(ou un vecteur ligne):

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

L'explication de ce code est assez simple. Il s'agit d'une fonction anonyme qui prend les deux entrées xet y. Nous effectuons la sommation pondérée (l'expression du numérateur de chaque coordonnée) dans une approche d'algèbre linéaire en utilisant la multiplication matrice-vecteur. En prenant le vecteur ydes masses et en le multipliant par la matrice des coordonnées xpar multiplication matrice-vecteur, vous calculeriez la somme pondérée des deux coordonnées individuellement, puis nous diviserions chacune de ces coordonnées par la somme des masses, trouvant ainsi le centre souhaité de masse renvoyée comme vecteur de ligne 1 x 2 pour chaque coordonnée respectivement.

Exemple d'exécutions

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

Essayez-le en ligne!

https://ideone.com/BzbQ3e

rayryeng - Réintégrer Monica
la source
1
Vous pouvez supprimer ;, et aussi 'en choisissant correctement le format d'entrée ( xcomme vecteur de ligne)
Luis Mendo
@DonMuesli Merci :) Réduction du nombre d'octets de 2.
rayryeng - Rétablir Monica
6

Gelée, 6 octets

S÷@×"S

ou

÷S$×"S

L'entrée se fait via deux arguments de ligne de commande, les masses d'abord, les coordonnées ensuite.

Essayez-le en ligne!

Explication

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
la source
6

Julia, 25 17 octets

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

Manqué l'approche évidente: / Appelez comme f([3 1;0 0;1 4], [2 4 1]).

Sp3000
la source
5

CJam, 14 octets

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

Une fonction sans nom attend la liste des paires de coordonnées et la liste des masses sur la pile (dans cet ordre) et laisse le centre de masse à leur place.

Testez-le ici.

Explication

_    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
la source
5

Perl 6, 36 33 30 octets

{[Z+](@^a Z»*»@^b) X/sum @b}
Raccourcis clavier
la source
4

Sérieusement, 16 octets

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

Prend les entrées en tant que [x-coords]\n[y-coords]\n[masses]et les sorties en tant quexbar\nybar

Essayez-le en ligne!

Explication:

╩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
la source
3

Haskell, 55 50 octets

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

Ceci définit une fonction binaire f, utilisée comme suit:

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

Voir réussir les deux cas de test.

Explication

Haskell n'est pas bien adapté au traitement de listes multidimensionnelles, donc je saute dans certains cerceaux ici. La première ligne définit un alias court pour zipWith, dont nous avons besoin deux fois. Fondamentalement, fest une fonction qui prend la liste des poids aet produit f a, une fonction qui prend la liste des positions et produit le centre de masse. f aest une composition de trois fonctions:

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
la source
3

JavaScript (ES6), 60 octets

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

Accepte un tableau de (x, y, masse) "triples" et renvoie un "tuple".

Neil
la source
Les parenthèses sont-elles [x,y,m]nécessaires? iirc, ils ne sont pas requis s'il n'y a qu'un seul argument d'entrée pour la fonction flèche.
Patrick Roberts
@PatrickRoberts Oui, ils sont nécessaires dans tous les cas, sauf celui un argument trivial d'exactement un standard.
Neil
3

R, 32 25 octets

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

éditer -7 octets en passant à l'algèbre matricielle (merci @ réponse Sp3000 Julia)

passer un tableau (matrice à 2 colonnes, x, y) comme coordonnées et vecteur mde poids, retourne un tableau avec les coordonnées requises

mnel
la source
2

PHP, 142 octets

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)];}
Vue éclatée
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) ];
}
Entrée requise
Array[Array]: [ [ mass1, mass2, ... ],
                [ xpos1, xpos2, ... ],
                [ ypos1, ypos2, ... ] ]
Revenir

Array: [ xbar, ybar ]


La p()fonction est une carte de base, multipliant chaque [m]valeur par la valeur [x]ou correspondante [y]. La c()fonction prend le Array[Array], présente les fonctions array_sumet array_mappour l'espace, puis calcule Σmx/Σmet Σmy/Σm.

Il pourrait être possible de transformer le calcul lui-même en fonction de l'espace, verra.

ricdesi
la source
2

Mathcad, 8 "octets"

Je ne sais pas à quoi je ne pensais pas dans ma réponse précédente. Voici un moyen plus court d'utiliser correctement la multiplication matricielle. La variable p contient les données - si le réglage de la variable compte pour le total, ajoutez ensuite 2 "octets" supplémentaires (création de la table d'entrée = 1 octet, nom de la variable = 1 octet).

entrez la description de l'image ici

Stuart Bruff
la source
1

Python 3, 63 octets

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

Les opérations vectorielles sur les listes sont longues: /

Il s'agit d'une fonction lambda anonyme - donnez-lui un nom et appelez comme f([[0,2],[3,4],[0,1],[1,1]],[2,6,2,10]).

Sp3000
la source
1

Python 3, 95 90 88 octets

Solution

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

Résultats

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

grâce à @Zgarb économisant 2 octets


Une solution récursive pour le plaisir (95 octets)

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]

Résultats

>>> 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
la source
2
Je pense que cela *([c]+[m])pourrait être raccourci *[c,m].
Zgarb
0

Axiome, 158 octets

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

le défouler

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

résultats

(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
la source