Центр маси з переліку координат та їх маси


20

Ось швидкий випуск у понеділок вранці ...

Напишіть функцію або програму найменшою кількістю байтів, які:

  • Приймає як вхід список [x,y]координат
  • Приймає як вхід список [x,y]відповідних мас координат
  • Виводиться обчислений центр маси у вигляді [xBar,yBar].

Примітка:

  • Введення можна приймати в будь-якій формі, якщо використовується масив.

Центр маси можна обчислити за такою формулою: Центр масових обчислень

Простий англійською мовою ...

  • Щоб знайти xBar, помножте кожну масу на відповідну x координату, підсумовуйте отриманий список і діліть його на суму всіх мас.
  • Щоб знайти yBar, помножте кожну масу на її відповідну координату y, підсумовуйте отриманий список і діліть його на суму всіх мас.

Приклад 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]

Випробування:

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

Це код-гольф, тому виграє найменша кількість байтів!


Оскільки це просто "обчислення середньозваженого середнього значення векторів", я був би дуже здивований, якщо ми цього не робили раніше. (На даний момент я нічого не можу знайти.)
Мартін Ендер

@ MartinBüttner Я також виглядав, і не міг знайти жодного. Якщо це дупа, сміливо закривайте її.
Пан Громадський

Чи можна взяти вхід в іншому порядку? Або у формі [x,y,m],[x,y,m]...:?
FryAmTheEggman

@FryAmTheEggman Питання відредаговано для дійсних даних.
Пан Громадський

@MrPublic: А як щодо [(x1,y1,m1), (x2,y2,m2)], наприклад, список кортежів? Або не має значення, чи аргументи є кортежами, списками або масивами? А як щодо трьох списків / масивів?
Зета

Відповіді:


21

MATL , 6 5 байт

ys/Y*

Формат введення - вектор рядків з масами, потім матриця з двома стовпцями з координатами (у яких пробіли чи коми не є обов'язковими).

  • Перший приклад:

    [2, 6, 2, 10]
    [0,2; 3,4; 0,1; 1,1]
    
  • Другий приклад:

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

Спробуйте в Інтернеті!

Пояснення

Нехай mпозначають вектор мас (перший вхід) та cматрицю координат (другий вхід).

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досить корисно !! +1
Девід

@David Так! У поєднанні з неявним вкладом це робить багато справ у цьому випадку :-)
Луїс Мендо

7

Математика, 10 байт

#.#2/Tr@#&

Приклад:

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

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

1
Я ніколи не використовував Dot. Але я побачу ваше використання вище!
DavidC

7

Mathcad, 19 "байт"

введіть тут опис зображення

  • Використовує таблиці Mathcad для введення даних
  • Використовує вбудований векторний скалярний продукт Mathcad для множення осі ординат і маси
  • Використовує вбудований оператор підсумовування Mathcad для загальної маси

Оскільки Mathcad використовує 2D "дошку" та спеціальні оператори (наприклад, оператор підсумовування, інтегральний оператор) та зберігає у форматі XML, фактичний робочий аркуш може містити кілька сотень (або більше) символів. Для цілей Code Golf я взяв Mathcad "кількість байтів" як кількість символів або операторів, які повинен ввести користувач, щоб створити робочий аркуш.

Перша (програмна) версія виклику займає 19 "байт", використовуючи це визначення, а версія функції займає 41 "байт".


3
Вперше тут я бачив рішення Matcad. Дуже хороша. +1.
rayryeng

Дякую, райріенг. Це, мабуть, тому, що це чимало завдання зробити деякі «дірки» на «курсі», враховуючи, що Mathcad має лише основні рядкові функції і не має читаного для людини текстового вихідного коду.
Стюарт Брюфф

6

MATLAB / Октава, 18 16 байт

Дякуємо користувачеві beaker та Don Muesli за видалення 2-х байт!

Враховуючи, що координати знаходяться в N x 2матриці, xде перший стовпець є координатою X, а другий стовпець - координатою Y, а маси знаходяться в 1 x Nматриці y(або векторі рядка):

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

Пояснення цього коду досить прямо. Це анонімна функція, яка бере два входи xта y. Ми виконуємо зважене підсумовування (вираження чисельника кожної координати) в лінійному підході до алгебри, використовуючи множення матричного вектора. Взявши вектор yмас і помноживши це на матрицю координат xна матричне-векторне множення, ви обчислили б зважену суму обох координат окремо, то ділимо кожну з цих координат на суму мас, знаходячи таким чином потрібний центр маса повертається у вигляді вектора 1 х 2 рядка для кожної координати відповідно.

Приклад виконання

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

Спробуйте в Інтернеті!

https://ideone.com/BzbQ3e


1
Ви можете видалити ;, а також 'правильно вибравши формат введення ( xяк вектор рядка)
Луїс Мендо

@DonMuesli Спасибі :) Зменшив кількість байтів на 2.
rayryeng - Відновити Моніку

6

Желе, 6 байт

S÷@×"S

або

÷S$×"S

Введення здійснюється через два аргументи командного рядка, по-перше, маси, координує друге.

Спробуйте в Інтернеті!

Пояснення

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

або

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

6

Джулія, 25 17 байт

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

Пропустив очевидний підхід: / Дзвінок подобається f([3 1;0 0;1 4], [2 4 1]).


5

CJam, 14 байт

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

Безіменна функція з очікує на перелік пар координат і список мас на стеку (у такому порядку) і залишає центр маси на їх місці.

Тестуйте це тут.

Пояснення

_    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

Серйозно, 16 байт

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

Приймає введення як [x-coords]\n[y-coords]\n[masses], а виводить якxbar\nybar

Спробуйте в Інтернеті!

Пояснення:

╩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 байт

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

Це визначає двійкову функцію f, яка використовується наступним чином:

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

Дивіться, як проходять обидва тестові справи.

Пояснення

Haskell не дуже підходить для обробки багатовимірних списків, тому тут я перестрибую кілька обручів. Перший рядок визначає короткий псевдонім для zipWith, який нам потрібен двічі. В основному, fце функція, яка бере список ваг aі виробляєf a , функція, яка займає список позицій і виробляє центр маси. f aявляє собою склад з трьох функцій:

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 байт

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

Приймає масив (x, y, маса) "трійки" і повертає "кортеж".


Чи потрібні круглі дужки [x,y,m]? iirc, вони не потрібні, якщо для стрілки функціонує лише один вхідний аргумент.
Патрік Робертс

@PatrickRoberts Так, вони потрібні у всіх випадках, за винятком одного тривіального одного точно одного стандартного аргументу.
Ніл

3

R, 32 25 байт

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

редагувати -7 байт шляхом переходу на матричну алгебру (спасибі @ Sp3000 відповідь Юлії)

передає масив (матриця з 2 стовпцями, х, у) як координати та вектор mваг, повертає масив із необхідними координатами


2

PHP, 142 байти

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)];}
Вибухнув вигляд
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) ];
}
Обов’язкове введення
Array[Array]: [ [ mass1, mass2, ... ],
                [ xpos1, xpos2, ... ],
                [ ypos1, ypos2, ... ] ]
Повернення

Array: [ xbar, ybar ]


p()Функція є базовою картою, множення кожного [m]значення з відповідним [x]або [y]значенням. c()Функція приймає в Array[Array], представлена array_sumі array_mapфункції для простору, а потім обчислює Σmx/ΣmіΣmy/Σm .

Можливо, можна перетворити сам обчислення у функцію для простору, побачимо.


2

Mathcad, 8 "байт"

Я не знаю, про що я не думав у своїй попередній відповіді. Ось коротший спосіб правильного використання матричного множення. Змінна p містить дані - якщо встановлення змінної зараховується до загальної кількості, тоді додайте ще 2 "байти" (створення таблиці введення = 1 байт, ім'я змінної = 1 байт).

введіть тут опис зображення


1

Python 3, 63 байти

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

Векторні операції в списках довгі: /

Це анонімна лямбда-функція - дайте їй ім’я та дзвінок як f([[0,2],[3,4],[0,1],[1,1]],[2,6,2,10]).


1

Python 3, 95 90 88 байт

Рішення

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

Результати

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

завдяки @Zgarb економив 2 байти


Рекурсивне рішення для розваг (95 байт)

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]

Результати

>>> 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
Я думаю, що це *([c]+[m])можна було б скоротити *[c,m].
Згарб

0

Аксіома, 158 байт

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

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

результати

(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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.