Уникальные указатели и правило 3

Использовать встроенную функцию struct для объединения столбцов CODE и DATE и использовать этот новый столбец структуры в функции агрегации collect_list. А в функции udf сортировать по DATE и собирать CODE в качестве - выделенной строки

import org.apache.spark.sql.functions._
def sortAndStringUdf = udf((codeDate: Seq[Row])=> codeDate.sortBy(row => row.getAs[Long]("DATE")).map(row => row.getAs[String]("CODE")).mkString("-"))

df.withColumn("codeDate", struct(col("CODE"), col("DATE").cast("timestamp").cast("long").as("DATE")))
      .groupBy("KEY").agg(sortAndStringUdf(collect_list("codeDate")).as("CODE"))

, которая должна дать вам

+---+--------------+
|KEY|          CODE|
+---+--------------+
| 68|         JO-PL|
| 67|JL-PO-PL-JL-JL|
| 66|         PL-PL|
+---+--------------+

Я надеюсь, что ответ будет полезен

Update

Я уверен, что это будет быстрее, чем использование функции udf

df.withColumn("codeDate", struct(col("DATE").cast("timestamp").cast("long").as("DATE"), col("CODE")))
  .groupBy("KEY")
  .agg(concat_ws("-", expr("sort_array(collect_list(codeDate)).CODE")).alias("CODE"))
  .show(false)

, который должен дать вам тот же результат, что и выше

3
задан C.Mennell 13 July 2018 в 10:06
поделиться

2 ответа

Во-первых, я думаю, что сигнатура вашей функции clone может быть

virtual std::unique_ptr<A> clone() = 0;

, так как вы хотите получить глубокие копии экземпляров A и исключительного права собственности в B. Во-вторых, вам действительно нужно определить конструктор копирования для вашего класса, когда вы хотите, чтобы он был скопирован. То же самое для оператора присваивания. Это связано с тем, что std::unique_ptr - это тип только для перемещения, что мешает компилятору генерировать реализации по умолчанию.

Другие специальные функции-члены не нужны, хотя они могут иметь смысл. Компилятор не будет генерировать конструктор перемещения и переместить оператор назначения для вас (поскольку вы отправляете свои собственные функции копирования / назначения), хотя в вашем случае вы можете = default; их легко. Деструктор можно точно определить с помощью = default;, который будет соответствовать директиве ядра .

Обратите внимание, что определение деструктора через = default должно выполняться в единица перевода, поскольку std::unique_ptr требует, чтобы полный тип был известен при освобождении его ресурса.

Независимо от того, нужен ли вам конструктор по умолчанию, полностью зависит от того, как вы хотите использовать класс B.

3
ответ дан lubgr 17 August 2018 в 13:11
поделиться
  • 1
    Спасибо за объяснение lubgr. Я знал о ограничениях на копирование и назначение с помощью уникальных указателей, но не в концепции типов только для перемещения. Я никогда не встречал '= default;' до этого, но я вижу, что я очень много использую его. – C.Mennell 13 July 2018 в 14:09

Как сказал @lubgr в своем ответе, вы должны вернуть unique_ptr не сырой из функции clone. В любом случае, перейдя к вашим вопросам:

  1. Вам нужен конструктор копирования в B? Ну, это зависит от ваших вариантов использования, но если вы копируете объекты класса B, вам может понадобиться один. Но, как вы сказали, вы делаете это довольно часто, поэтому было бы разумнее рассмотреть более общий подход. Один из них будет создавать оболочку для unique_ptr, которая будет иметь конструктор копирования и которая сделает глубокую копию этого указателя в этом конструкторе копирования. Рассмотрим следующий пример:
    template<class T>
    class unique_ptr_wrap {
    public:
        unique_ptr_wrap(std::unique_ptr< T > _ptr) : m_ptr(std::move(_ptr)){}
    
        unique_ptr_wrap(const unique_ptr_wrap &_wrap){
            m_ptr = _wrap->clone();
        }
    
        unique_ptr_wrap(unique_ptr_wrap &&_wrap){
            m_ptr = std::move(_wrap.m_ptr);
        }
    
        T *operator->() const {
            return m_ptr.get();
        }
    
        T &operator*() const {
            return *m_ptr;
        }
    private:
        std::unique_ptr< T > m_ptr;
    };
    
  2. Это снова зависит от ваших потребностей. Я лично рекомендовал бы также перегружать конструктор перемещения, чтобы он использовал менее динамические распределения (но это может быть предварительная оптимизация, которая является корнем всего зла).
1
ответ дан bartop 17 August 2018 в 13:11
поделиться
  • 1
    Спасибо, бартоп. Конечно, вы правы, что мне нужен конструктор копирования для B, зависит от того, действительно ли он используется! В моем случае большинство классов будут (надеюсь) использоваться другими людьми, поэтому я так и предполагаю. Я думаю, что ваш ответ очень близок к тому, что я буду реализовывать: я добавлю оператор присваивания и базовый класс для клонируемых типов (и убедитесь, что T получен из клонируемого базового класса). – C.Mennell 13 July 2018 в 13:57
Другие вопросы по тегам:

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