Центр масс из списка координат и их массы


20

Вот быстрый вызов в понедельник утром ...

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

  • Принимает в качестве ввода список [x,y]координат
  • В качестве входных данных принимает список [x,y]соответствующих масс координат.
  • Выводит рассчитанный центр масс в виде [xBar,yBar].

Замечания:

  • Входные данные могут быть приняты в любой форме, если используется массив.

Центр масс можно рассчитать по следующей формуле: Центр массовых расчетов

На простом английском ...

  • Чтобы найти xBar, умножьте каждую массу на соответствующую ей координату x, суммируйте полученный список и разделите его на сумму всех масс.
  • Чтобы найти yBar, умножьте каждую массу на ее соответствующую координату y, суммируйте полученный список и разделите его на сумму всех масс.

Тривиальный пример 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
Дэвид

@ Дэвид Да! В сочетании с неявным вводом, в этом случае он многое делает :-)
Луис Мендо,

7

Mathematica, 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 / Octave, 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 x 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, mass) «троек» и возвращает «кортеж».


Нужны ли круглые скобки [x,y,m]? iirc, они не требуются, если есть только один входной аргумент для функции стрелки.
Патрик Робертс

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

3

R, 32 25 байт

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

отредактируйте -7 байтов, переключившись на матричную алгебру (спасибо @ Sp3000 Julia answer)

передать массив (матрицу с 2 столбцами, x, y) в качестве координат и вектора 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])

раскрутить это

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