массив структур или структуры массивов?

Если кому-то это нужно, вот тот же фрагмент кода, но для Xamarin.Android.

/**
 *               DO WHAT YOU WANT TO PUBLIC LICENSE
 *                    Version 1, December 2017
 * 
 * Copyright (C) 2017 Nathan Westfall
 * 
 * Everyone is permitted to copy and distribute verbatim or modified
 * copies of this license document, and changing it is allowed as long
 * as the name is changed.
 * 
 *            DO WHAT YOU WANT TO PUBLIC LICENSE
 *   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 * 
 *  0. You just DO WHAT YOU WANT TO.
 */

using Android.Content;
using Android.Runtime;
using Android.Widget;
using Android.Util;
using Android.Text;

using Java.Lang;

namespace My.Text
{
    public class AutoResizeTextView : TextView
    {
        public const float MIN_TEXT_SIZE = 20;

        public interface OnTextResizeListener
        {
            void OnTextResize(TextView textView, float oldSize, float newSize);
        }

        private const string mEllipsis = "...";

        private OnTextResizeListener mTextResizeListener;

        private bool mNeedsResize = false;

        private float mTextSize;

        private float mMaxTextSize = 0;

        private float mMinTextSize = MIN_TEXT_SIZE;

        private float mSpacingMult = 1.0f;

        private float mSpacingAdd = 0.0f;

        public bool AddEllipsis { get; set; } = true;

        public AutoResizeTextView(Context context) : this(context, null) { }

        public AutoResizeTextView(Context context, IAttributeSet attrs) : this(context, attrs, 0) { }

        public AutoResizeTextView(Context context, IAttributeSet attrs, int defStyle): base(context, attrs, defStyle)
        {
            mTextSize = TextSize;
        }

        protected override void OnTextChanged(ICharSequence text, int start, int lengthBefore, int lengthAfter)
        {
            base.OnTextChanged(text, start, lengthBefore, lengthAfter);

            mNeedsResize = true;

            ResetTextSize();
        }

        protected override void OnSizeChanged(int w, int h, int oldw, int oldh)
        {
            base.OnSizeChanged(w, h, oldw, oldh);

            if (w != oldw || h != oldh)
                mNeedsResize = true;
        }

        public void SetOnResizeListener(OnTextResizeListener listener)
        {
            mTextResizeListener = listener;
        }

        public override void SetTextSize([GeneratedEnum] ComplexUnitType unit, float size)
        {
            base.SetTextSize(unit, size);

            mTextSize = TextSize;
        }

        public override void SetLineSpacing(float add, float mult)
        {
            base.SetLineSpacing(add, mult);

            mSpacingMult = mult;
            mSpacingAdd = add;
        }

        public void SetMaxTextSize(float maxTextSize)
        {
            mMaxTextSize = maxTextSize;
            RequestLayout();
            Invalidate();
        }

        public float GetMaxTextSize()
        {
            return mMaxTextSize;
        }

        public void SetMinTextSize(float minTextSize)
        {
            mMinTextSize = minTextSize;
            RequestLayout();
            Invalidate();
        }

        public float GetMinTextSize()
        {
            return mMinTextSize;
        }

        public void ResetTextSize()
        {
            if(mTextSize > 0)
            {
                base.SetTextSize(ComplexUnitType.Px, mTextSize);
                mMaxTextSize = mTextSize;
            }
        }

        protected override void OnLayout(bool changed, int left, int top, int right, int bottom)
        {
            if(changed || mNeedsResize)
            {
                int widthLimit = (right - left) - CompoundPaddingLeft - CompoundPaddingRight;
                int heightLimit = (bottom - top) - CompoundPaddingBottom - CompoundPaddingTop;
                ResizeText(widthLimit, heightLimit);
            }
            base.OnLayout(changed, left, top, right, bottom);

            base.OnLayout(changed, left, top, right, bottom);
        }

        public void ResizeText()
        {
            int heightLimit = Height - PaddingBottom - PaddingTop;
            int widthLimit = Width - PaddingLeft - PaddingRight;
            ResizeText(widthLimit, heightLimit);
        }

        public void ResizeText(int width, int height)
        {
            var text = TextFormatted;
            if (text == null || text.Length() == 0 || height <= 0 || width <= 0 || mTextSize == 0)
                return;

            if (TransformationMethod != null)
                text = TransformationMethod.GetTransformationFormatted(TextFormatted, this);

            TextPaint textPaint = Paint;

            float oldTextSize = textPaint.TextSize;
            float targetTextSize = mMaxTextSize > 0 ? System.Math.Min(mTextSize, mMaxTextSize) : mTextSize;

            int textHeight = GetTextHeight(text, textPaint, width, targetTextSize);

            while(textHeight > height && targetTextSize > mMinTextSize)
            {
                targetTextSize = System.Math.Max(targetTextSize - 2, mMinTextSize);
                textHeight = GetTextHeight(text, textPaint, width, targetTextSize);
            }

            if(AddEllipsis && targetTextSize == mMinTextSize && textHeight > height)
            {
                TextPaint paint = new TextPaint(textPaint);

                StaticLayout layout = new StaticLayout(text, paint, width, Layout.Alignment.AlignNormal, mSpacingMult, mSpacingAdd, false);
                if(layout.LineCount > 0)
                {
                    int lastLine = layout.GetLineForVertical(height) - 1;
                    if (lastLine < 0)
                        SetText("", BufferType.Normal);
                    else
                    {
                        int start = layout.GetLineStart(lastLine);
                        int end = layout.GetLineEnd(lastLine);
                        float lineWidth = layout.GetLineWidth(lastLine);
                        float ellipseWidth = textPaint.MeasureText(mEllipsis);

                        while (width < lineWidth + ellipseWidth)
                            lineWidth = textPaint.MeasureText(text.SubSequence(start, --end + 1).ToString());
                        SetText(text.SubSequence(0, end) + mEllipsis, BufferType.Normal);
                    }
                }
            }

            SetTextSize(ComplexUnitType.Px, targetTextSize);
            SetLineSpacing(mSpacingAdd, mSpacingMult);

            mTextResizeListener?.OnTextResize(this, oldTextSize, targetTextSize);

            mNeedsResize = false;
        }

        private int GetTextHeight(ICharSequence source, TextPaint paint, int width, float textSize)
        {
            TextPaint paintCopy = new TextPaint(paint);
            paintCopy.TextSize = textSize;
            StaticLayout layout = new StaticLayout(source, paintCopy, width, Layout.Alignment.AlignNormal, mSpacingMult, mSpacingAdd, false);
            return layout.Height;
        }
    }
}
6
задан Jason S 1 February 2017 в 05:03
поделиться

8 ответов

Вторая версия намного хуже . Вместо изменения размера одного массива, вы изменяете размер трех массивов при вставке или удалении. Более того, вторая версия приведет к созданию гораздо большего количества временных объектов, и это будет происходить при доступе. Это может привести к большому количеству мусора (с точки зрения сборки мусора). Нехорошо.

В общем, вы должны беспокоиться о том, как вы используете объекты, задолго до того, как задумываться о производительности. Итак, у вас есть запись с тремя полями или тремя массивами. Какой из них более точно отображает то, что вы моделируете? Под этим я подразумеваю, когда вы вставляете или удаляете элемент, вы делаете один из трех массивов или все три как блок?

Я подозреваю, что это последнее, и в этом случае первое имеет гораздо больший смысл.

Если ты'

5
ответ дан 8 December 2019 в 02:46
поделиться

Как вы собираетесь получить доступ к данным? Если доступ к полям всегда связан, используйте первый вариант, если вы собираетесь обрабатывать поля самостоятельно, тогда лучше второй вариант.

См. Эту статью в википедии: Parallel Array

Хорошим примером того, когда удобнее иметь отдельные массивы, может служить моделирование, при котором числовые данные упаковываются вместе в один и тот же массив, а другие атрибуты, такие как имя, цвет и т. Д., Доступны только для представления данных в других массив.

3
ответ дан 8 December 2019 в 02:46
поделиться

Обратите внимание, что второй подход может отрицательно повлиять на поведение кэширования. Если вы хотите получить доступ к одной записи за раз, вам лучше, чтобы эта запись не была разбросана повсюду.

Кроме того, единственная память, которую вы выигрываете во втором подходе, (возможно) связана с выравниванием членов. (и необходимо выделить отдельный объект). В противном случае они асимптотически используют одинаковое количество памяти. Первый вариант намного лучше из-за местоположения, IMO

2
ответ дан 8 December 2019 в 02:46
поделиться

Всякий раз, когда я пытался выполнить обработку чисел на Java, мне всегда приходилось возвращаться к кодированию в стиле C (т.е. близкому к вашему варианту 2). Это минимизировало количество объектов, плавающих в вашей системе, поскольку вместо 1000000 объектов у вас есть только 3. Мне удалось провести небольшой анализ БПФ звуковых данных в реальном времени с использованием стиля C, и это было слишком медленно использует предметы.

2
ответ дан 8 December 2019 в 02:46
поделиться

Я бы тоже выбрал версию ArrayList, так что мне не нужно беспокоиться о ее расширении. Вам нужен столбец, например, доступ к значениям? Каков ваш сценарий, стоящий за вашим вопросом?

Edit Вы также можете использовать обычную матрицу long [] [] . Я не знаю, как вы передаете столбцы в Matlab, но я думаю, вы не получите большой скорости с хранилищем на основе столбцов, скорее всего, вы потеряете скорость вычислений Java.

1
ответ дан 8 December 2019 в 02:46
поделиться

Поскольку вы делаете поля int [] окончательными, вы застряли только на одной инициализации массива, и все. Таким образом, если вам нужно 10 ^ 6 field1, Java потребуется выделить столько памяти для каждого из этих int [], потому что вы не можете переназначить размер этих массивов. С помощью ArrayList, если вы заранее не знаете количество записей и потенциально будете удалять записи, вы экономите много места заранее, а затем и позже, когда будете удалять записи.

1
ответ дан 8 December 2019 в 02:46
поделиться

Я бы выбрал первый метод (массив структур) , если вы не обращаетесь к хранилищу относительно редко и не сталкиваетесь с серьезными проблемами нехватки памяти.

Первая версия в основном хранит объекты в их «естественной» форме (+1 BTW за использование неизменяемых записей). Это использует немного больше памяти из-за накладных расходов на каждый объект (вероятно, около 8-16 байтов в зависимости от вашей JVM), но очень хорошо подходит для доступа и возврата объектов в удобной и понятной человеку форме за один простой шаг.

Вторая версия использует меньше памяти в целом, но выделение нового объекта при каждом "получении" - довольно уродливое решение, которое не будет работать хорошо, если доступы часты.

Некоторые другие возможности для рассмотрения:

Интересным «крайним» вариантом было бы взять вторую версию, но написать свои алгоритмы / методы доступа для непосредственного взаимодействия с нижележащими массивами. Это явно приведет к сложным взаимозависимостям и некрасивому коду, но, вероятно, даст вам абсолютную лучшую производительность, если вам это действительно нужно.Этот подход довольно часто используется для интенсивных графических приложений, таких как управление большим массивом трехмерных координат.

«Гибридный» вариант - хранить базовые данные в структуре массивов, как во второй версии, но кэшировать объекты, к которым осуществляется доступ, в HashMap, чтобы вы генерировали объект только при первом доступе к определенному индексу. Может иметь смысл, если когда-либо будет доступна только небольшая часть объектов, но все данные нужны «на всякий случай».

2
ответ дан 8 December 2019 в 02:46
поделиться

(Не прямой ответ, но я думаю, что он должен быть дан)

Из вашего комментария:

"cletus - я очень уважаю ваши мысли и мнения, но вы дали мне точку зрения высокоуровневого программирования и дизайна программного обеспечения, а это не то, что я ищу. Я не могу научиться игнорировать оптимизацию, пока не получу интуитивное чувство стоимости различных стилей реализации, и/или способность оценить эти затраты. - Jason S Jul 14 '09 at 14:27"

Вы всегда должны игнорировать оптимизацию, пока она не проявит себя как проблема. Самое главное, чтобы система была удобна для разработчика (чтобы он мог сделать ее удобной для пользователя). Существует очень мало случаев, когда вы должны беспокоиться об оптимизации, на самом деле за ~20 лет профессионального кодирования я беспокоился об оптимизации всего два раза:

  1. Написание программы, основной целью которой было быть быстрее другого продукта
  2. Написание приложения для смартфона с намерением уменьшить количество данных, передаваемых между клиентом и сервером

В первом случае я написал код, затем прогнал его через профайлер, когда я хотел что-то сделать и не был уверен, какой подход лучше (для скорости/памяти), я писал код одним способом и смотрел результат в профайлере, затем писал код другим способом и смотрел результат. Затем я выбирал более быстрый из двух вариантов. Это работает, и вы узнаете много нового о низкоуровневых решениях. Однако я не допускал, чтобы это влияло на классы более высокого уровня".

Во втором случае не было программирования, но я сделал то же самое: посмотрел на передаваемые данные и выяснил, как уменьшить количество передаваемых сообщений и количество передаваемых байтов.

Если ваш код понятен, то его будет легче ускорить, когда вы обнаружите, что он медленный. Как сказал Клетус в своем ответе, вы изменяете размер один раз - против трех раз... один раз будет быстрее, чем три. С точки зрения высшего руководства, однократное проще для понимания, чем трехкратное, поэтому оно с большей вероятностью будет правильным.

Лично я предпочитаю получить правильный ответ медленно, чем неправильный ответ быстро. Как только я узнаю, как получить правильный ответ, я смогу найти, где система работает медленно, и заменить эти части системы более быстрыми реализациями.

2
ответ дан 8 December 2019 в 02:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: