Использовать встроенную функцию 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|
+---+--------------+
Я надеюсь, что ответ будет полезен
Я уверен, что это будет быстрее, чем использование функции 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)
, который должен дать вам тот же результат, что и выше
Во-первых, я думаю, что сигнатура вашей функции clone может быть
virtual std::unique_ptr<A> clone() = 0;
, так как вы хотите получить глубокие копии экземпляров A
и исключительного права собственности в B
. Во-вторых, вам действительно нужно определить конструктор копирования для вашего класса, когда вы хотите, чтобы он был скопирован. То же самое для оператора присваивания. Это связано с тем, что std::unique_ptr
- это тип только для перемещения, что мешает компилятору генерировать реализации по умолчанию.
Другие специальные функции-члены не нужны, хотя они могут иметь смысл. Компилятор не будет генерировать конструктор перемещения и переместить оператор назначения для вас (поскольку вы отправляете свои собственные функции копирования / назначения), хотя в вашем случае вы можете = default;
их легко. Деструктор можно точно определить с помощью = default;
, который будет соответствовать директиве ядра .
Обратите внимание, что определение деструктора через = default
должно выполняться в единица перевода, поскольку std::unique_ptr
требует, чтобы полный тип был известен при освобождении его ресурса.
Независимо от того, нужен ли вам конструктор по умолчанию, полностью зависит от того, как вы хотите использовать класс B
.
Как сказал @lubgr в своем ответе, вы должны вернуть unique_ptr
не сырой из функции clone
. В любом случае, перейдя к вашим вопросам:
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;
};