Глубоко клонируйте служебную [закрытую] рекомендацию

Некоторые предложения по улучшению производительности:

Вместо:

for($k=0;$k<$d;$k++){ 
    $median[$k] = $expenditure[$i+$k];
}

Использование:

$median = array_slice($expenditure, $i, $d);

В общем случае функции массива будут выполняться быстрее, чем циклы.

Другая другая идея заключается в снижении стоимости функции sort(). Вы можете сделать это, поддерживая массив $median, в основном отсортированный по всему. Таким образом, вместо того, чтобы брать срез каждый раз, вы нажимаете одно значение и извлекаете одно значение. Примерно так:

$median[$i+$d] = $expenditure[$i+$d]; // append a value
unset($median[$i]); // remove a value

Затем используйте asort для сортировки и сохранения ключевых ассоциаций:

asort($median);

По сути $median всегда будет окном в $expenditure размера г и поддерживает ключевые ассоциации. Вы можете инициализировать $median с самого начала, сначала взяв срез, используя: $median = array_slice($expenditure, $i, $d); вне цикла.

Очень грубо (сам не проверял):

function activityNotifications($expenditure, $d) {

    $size = sizeof($expenditure);
    $count = 0 ;
    $median = array_slice($expenditure, 0, $d, TRUE); // initial slice with keys
    for($i=$d;$i<$size;$i++){

        $median[$i]=$expenditure[$i];
        unset($median[$i-$d]);
        asort($median);

        $median_values = array_values($median);
        if($d%2 == 1){
            $middle = $median_values[floor($d/2)];
        } else if($d%2 == 0){ 
            $value = $d/2;
            $middle = $median_values[$value] + $median_values[$value-1];
            $middle = $middle/2;
        }
        $value = $middle*2;

        if($value<=$expenditure[$d+$i]){
            $count++;
        }
    }
    return $count;
}

Обратите внимание, что приведенный выше код не будет работать напрямую, потому что, когда вы извлекаете свое значение средней точки, ключи не будут в порядке. Поэтому вам может понадобиться сначала использовать array_values (я добавил это выше).

72
задан Cœur 19 August 2017 в 17:00
поделиться

7 ответов

Я думаю, что предыдущий зеленый ответ был плохим , почему вы можете спросить?

  • Он добавляет много кода
  • Он требует, чтобы вы перечислили все поля для копирования и сделать это
  • Это не будет работать для списков при использовании clone () (Это то, что говорит clone () для HashMap: возвращает неглубокую копию этого экземпляра HashMap: сами ключи и значения не клонируются.) Так что вы в конечном итоге делаете это вручную (это заставляет меня плакать)

Да и между прочим сериализация - тоже плохо, возможно, вам придется добавлять Serializable повсюду (это тоже заставляет меня плакать).

Итак, каково решение:

Библиотека глубокого клонирования Java Библиотека клонирования - это небольшая библиотека Java с открытым исходным кодом (лицензия apache), которая глубоко клонирует объекты. Объекты не обязательно должны реализовывать интерфейс Cloneable. Фактически, эта библиотека может клонировать ЛЮБЫЕ объекты Java. Его можно использовать, например, в реализациях кеширования, если вы не хотите, чтобы кэшированный объект изменялся или всякий раз, когда вы хотите создать глубокую копию объектов.

Cloner cloner=new Cloner();
XX clone = cloner.deepClone(someObjectOfTypeXX);

Проверьте это на https://github.com/kostaskougios/cloning

64
ответ дан 24 November 2019 в 12:40
поделиться

Все подходы для копирования объектов в Java имеют серьезные дефекты:

Клон

  1. клон () метод защищен, таким образом, Вы не можете назвать его непосредственно, если рассматриваемый класс не переопределяет его с открытым методом.
  2. клон () не вызывает конструктора. Любой конструктор. Это выделит память, присвоит внутреннее class поле (который можно считать через getClass()), и скопируйте поля оригинала.

Для большего количества проблем с клоном (), посмотрите объект 11 из книги Joshua Bloch" Эффективный Java, Второй Выпуск "

Сериализирует

, Сериализируют, еще хуже; это имеет многие дефекты clone() и затем некоторые. У Joshua есть целая глава с четырьмя объектами для одной только этой темы.

Мое Решение

, которое Мое решение, добавляет новый интерфейс к моим проектам:

public interface Copyable<T> {
    T copy ();
    T createForCopy ();
    void copyTo (T dest);
}

код похож на это:

class Demo implements Copyable<Demo> {
    public Demo copy () {
        Demo copy = createForCopy ();
        copyTo (copy);
        return copy;
    }
    public Demo createForCopy () {
        return new Demo ();
    }
    public void copyTo (Demo dest)
        super.copyTo (dest);
        ...copy fields of Demo here...
    }
}

, К сожалению, я должен скопировать этот код во все свои объекты, но это всегда - тот же код, таким образом, я могу использовать редактора Eclipse шаблон. Преимущества:

  1. я могу решить, какого конструктора назвать и как инициализировать который поле.
  2. Инициализация, оказывается, в детерминированном порядке (корневой класс инстанцирует класс)
  3. , я могу снова использовать существующие объекты и перезаписать их
  4. Безопасный с точки зрения типов
  5. , Одиночные элементы остаются одиночные элементы

Для стандартных типов Java (как наборы, и т.д.), я использую служебный класс, который может скопировать их. Методы имеют флаги и обратные вызовы, таким образом, я могу управлять, как глубоко копия должна быть.

20
ответ дан Aaron Digulla 24 November 2019 в 12:40
поделиться

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

Выезд ответ Bruno для ссылки на Apache классы утилиты сериализации палаты общин , который будет очень полезен, если это будет маршрутом, Вы решаете взять.

10
ответ дан CorayThan 24 November 2019 в 12:40
поделиться

Одна возможность состоит в том, чтобы использовать сериализация :

Apache палата общин обеспечивает SerializationUtils

5
ответ дан CorayThan 24 November 2019 в 12:40
поделиться

Используйте сериализацию и затем десериализацию, но знайте, что этот подход работает только с сериализуемыми классами без переходных полей. Кроме того, Ваши одиночные элементы больше не будут одиночными элементами.

0
ответ дан Eric Leschinski 24 November 2019 в 12:40
поделиться

Поверхностное клонирование коллекции легко, но если вы хотите глубокое клонирование, библиотека, вероятно, подойдет вам лучше, чем ручное кодирование (поскольку вы хотите клонировать элементы внутри ] коллекцию).

Так же, как этот ответ , я использовал библиотеку Cloner и, в частности, протестировал ее производительность против XStream (который может «клонировать» путем сериализации, затем десериализация) и двоичная сериализация. Хотя XStream очень быстро сериализует в / из xml, Cloner намного быстрее при клонировании:

0,0851 мс: xstream (клонирование путем сериализации / десериализации)
0,0223 мс: двоичная сериализация (клонирование путем сериализации / десериализации)
0,0017 мс: клонер
* среднее время клонирования простого объекта (два поля) без открытого конструктора по умолчанию. Выполнить 10 000 раз.

Помимо скорости, есть еще несколько причин выбрать клонер:

  1. выполняет глубокое клонирование любого объекта (даже тех, которые вы не пишете самостоятельно)
  2. вам не нужно постоянно обновляйте свой метод clone () каждый раз, когда вы добавляете поле
  3. , вы можете клонировать объекты, у которых нет открытого конструктора по умолчанию
  4. работает с Spring
  5. (оптимизация) не клонирует известно неизменяемые объекты (например, Integer, String и т. д.)
  6. просты в использовании. Пример:

    cloner.deepClone (anyObject);

17
ответ дан 24 November 2019 в 12:40
поделиться

Я создатель библиотеки клонирования, которую представил Брэд. Это решение для клонирования объектов без необходимости писать дополнительный код (нет необходимости в сериализуемых объектах или методе impl clone ())

Это довольно быстро, как сказал Брэд, и недавно я загрузил версию, которая еще быстрее. Обратите внимание, что ручная реализация метода clone () будет быстрее, чем clone lib, но опять же, вам нужно будет написать много кода.

Cloner lib у меня работал довольно хорошо, так как я использую его в реализации кеширования для сайта с очень большой посещаемостью (~ 1 млн запросов / день). Кэш должен клонировать примерно 10 объектов на запрос. Достаточно надежный и стабильный. Но имейте в виду, что клонирование сопряжено с риском. Библиотека может быть настроена для печати каждого экземпляра класса, который она клонирует во время разработки. Таким образом вы можете проверить, клонирует ли он то, что, по вашему мнению, следует клонировать - графы объектов могут быть очень глубокими и содержать ссылки на удивительно большое количество объектов. С помощью clone lib вы можете указать ему не клонировать ненужные вам объекты, то есть одиночные объекты.

14
ответ дан 24 November 2019 в 12:40
поделиться
Другие вопросы по тегам:

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