Подсчет частоты упорядоченной последовательности (запусков) в данных с использованием SQL [duplicate]

Этот вопрос, кажется, очень популярен здесь в stackoverflow, поэтому я решил попробовать и дать лучший ответ, чтобы помочь людям, начинающим в мире iOS, как я.

Надеюсь, что этот ответ ясен

Передача данных вперед

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

В этом примере мы будем иметь ViewControllerA и ViewControllerB

Чтобы передать значение BOOL с ViewControllerA на ViewControllerB, мы сделали бы следующее.

  1. в ViewControllerB.h создать свойство для BOOL
    @property (nonatomic, assign) BOOL isSomethingEnabled;
    
  2. в ViewControllerA вам нужно рассказать об этом ViewControllerB, поэтому используйте
    #import "ViewControllerB.h"
    
    Затем, где вы хотите загрузить представление, например. didSelectRowAtIndex или несколько IBAction вам нужно установить свойство в ViewControllerB, прежде чем вы нажмете его на стек навигатора.
    ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
    viewControllerB.isSomethingEnabled = YES;
    [self pushViewController:viewControllerB animated:YES];
    
    Это установит isSomethingEnabled в значение ViewControllerB на BOOL значение YES.

Передача данных вперед с помощью Segues

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

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

. Итак, чтобы передать BOOL с ViewControllerA на ViewControllerB, мы выполнил бы следующее:

  1. в ViewControllerB.h создать свойство для BOOL
    @property (nonatomic, assign) BOOL isSomethingEnabled;
    
  2. в ViewControllerA, вам нужно рассказать об этом ViewControllerB поэтому используйте
    #import "ViewControllerB.h"
    
  3. Создайте выделение от ViewControllerA до ViewControllerB на раскадровке и дайте ему идентификатор, в этом примере мы будем называть его "showDetailSegue"
  4. Затем нам нужно добавить метод к ViewControllerA, который вызывается, когда выполняется какой-либо segue, из-за этого нам нужно определить, какой вызов был вызван, а затем что-то сделать. В нашем примере мы проверим "showDetailSegue", и если это будет выполнено, мы передадим наше значение BOOL в ViewControllerB
    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
        if([segue.identifier isEqualToString:@"showDetailSegue"]){
            ViewControllerB *controller = (ViewControllerB *)segue.destinationViewController;
            controller.isSomethingEnabled = YES;
        }
    }
    
    . Если у вас есть свои представления, встроенные в контроллер навигации, вам нужно немного изменить метод выше на следующие
    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
        if([segue.identifier isEqualToString:@"showDetailSegue"]){
            UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
            ViewControllerB *controller = (ViewControllerB *)navController.topViewController;
            controller.isSomethingEnabled = YES;
        }
    }
    
    Это установит isSomethingEnabled в ViewControllerB на значение BOOL YES.

Передача данных Назад

Чтобы передать данные с ViewControllerB ] до ViewControllerA вам нужно использовать Protocols and Delegates или Blocks , последний может использоваться как слабо связанный механизм для обратных вызовов.

To сделаем это, мы сделаем ViewControllerA делегатом из ViewControllerB. Это позволяет ViewControllerB отправить сообщение обратно на ViewControllerA, чтобы мы могли отправить данные назад.

Чтобы ViewControllerA был делегатом ViewControllerB, он должен соответствовать протоколу ViewControllerB, который мы должны указать. Это указывает ViewControllerA, какие методы он должен реализовать.

  1. В ViewControllerB.h ниже #import, но выше @interface вы указываете протокол.
    @class ViewControllerB;
    
    @protocol ViewControllerBDelegate 
    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;
    @end
    
  2. далее в ViewControllerB.h вам нужно настроить свойство delegate и синтезировать в ViewControllerB.m
    @property (nonatomic, weak) id  delegate;
    
  3. В ViewControllerB мы вызываем сообщение на delegate, когда мы выходим на контроллер вида.
    NSString *itemToPassBack = @"Pass this value back to ViewControllerA";
    [self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
    
  4. Это для ViewControllerB. Теперь в ViewControllerA.h скажите ViewControllerA, чтобы импортировать ViewControllerB и соответствовать его протоколу.
    #import "ViewControllerB.h"
    
    @interface ViewControllerA : UIViewController 
    
  5. В ViewControllerA.m реализуем следующий метод из нашего протокола
    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
    {
        NSLog(@"This was returned from ViewControllerB %@",item);
    }
    
  6. . Перед нажатием viewControllerB в стек навигации нам нужно сообщить ViewControllerB, что ViewControllerA является его делегатом, иначе мы получим сообщение об ошибке.
    ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
    viewControllerB.delegate = self
    [[self navigationController] pushViewController:viewControllerB animated:YES];
    

Ссылки

24
задан zero323 23 September 2015 в 17:00
поделиться

5 ответов

Прежде чем продолжить: Эта операция еще одна groupByKey.


Не совсем сжатое или эффективное решение, но вы можете использовать UserDefinedAggregateFunction, введенный в Spark 1.5.0:

object GroupConcat extends UserDefinedAggregateFunction {
    def inputSchema = new StructType().add("x", StringType)
    def bufferSchema = new StructType().add("buff", ArrayType(StringType))
    def dataType = StringType
    def deterministic = true 

    def initialize(buffer: MutableAggregationBuffer) = {
      buffer.update(0, ArrayBuffer.empty[String])
    }

    def update(buffer: MutableAggregationBuffer, input: Row) = {
      if (!input.isNullAt(0)) 
        buffer.update(0, buffer.getSeq[String](0) :+ input.getString(0))
    }

    def merge(buffer1: MutableAggregationBuffer, buffer2: Row) = {
      buffer1.update(0, buffer1.getSeq[String](0) ++ buffer2.getSeq[String](0))
    }

    def evaluate(buffer: Row) = UTF8String.fromString(
      buffer.getSeq[String](0).mkString(","))
}

Пример использования:

val df = sc.parallelize(Seq(
  ("username1", "friend1"),
  ("username1", "friend2"),
  ("username2", "friend1"),
  ("username2", "friend3")
)).toDF("username", "friend")

df.groupBy($"username").agg(GroupConcat($"friend")).show

## +---------+---------------+
## | username|        friends|
## +---------+---------------+
## |username1|friend1,friend2|
## |username2|friend1,friend3|
## +---------+---------------+

Вы также можете создать оболочку Python, как показано в Spark: как сопоставить Python с Scala или Java User Defined Functions?

На практике может быть быстрее извлечь RDD, groupByKey, mkString и перестроить DataFrame.

Вы можете получить аналогичный эффект, объединив collect_list (Spark> = 1.6.0) с concat_ws:

import org.apache.spark.sql.functions.{collect_list, udf, lit}

df.groupBy($"username")
  .agg(concat_ws(",", collect_list($"friend")).alias("friends"))
34
ответ дан Community 24 August 2018 в 20:58
поделиться

Язык: Scala Spark version: 1.5.2

У меня была такая же проблема, а также попытался разрешить ее с помощью udfs, но, к сожалению, это привело к появлению большего количества проблем позже в коде из-за тип несоответствий. Я смог обойти это, сначала преобразовывая DF в RDD, а затем группируя и обрабатывая данные желаемым способом, а затем преобразовывая RDD обратно в DF следующим образом:

val df = sc
     .parallelize(Seq(
        ("username1", "friend1"),
        ("username1", "friend2"),
        ("username2", "friend1"),
        ("username2", "friend3")))
     .toDF("username", "friend")

+---------+-------+
| username| friend|
+---------+-------+
|username1|friend1|
|username1|friend2|
|username2|friend1|
|username2|friend3|
+---------+-------+

val dfGRPD = df.map(Row => (Row(0), Row(1)))
     .groupByKey()
     .map{ case(username:String, groupOfFriends:Iterable[String]) => (username, groupOfFriends.mkString(","))}
     .toDF("username", "groupOfFriends")

+---------+---------------+
| username| groupOfFriends|
+---------+---------------+
|username1|friend2,friend1|
|username2|friend3,friend1|
+---------+---------------+
2
ответ дан agent_C.Hdj 24 August 2018 в 20:58
поделиться

Вы можете попробовать функцию collect_list

sqlContext.sql("select A, collect_list(B), collect_list(C) from Table1 group by A

Или вы можете зарегистрировать UDF что-то вроде

sqlContext.udf.register("myzip",(a:Long,b:Long)=>(a+","+b))

, и вы можете использовать эту функцию в запросе

sqlConttext.sql("select A,collect_list(myzip(B,C)) from tbl group by A")
12
ответ дан iec2011007 24 August 2018 в 20:58
поделиться

Один способ сделать это с помощью pyspark & ​​lt; 1.6, который, к сожалению, не поддерживает определяемую пользователем агрегированную функцию:

byUsername = df.rdd.reduceByKey(lambda x, y: x + ", " + y)

, и если вы хотите снова сделать это:

sqlContext.createDataFrame(byUsername, ["username", "friends"])

Начиная с версии 1.6, вы может использовать collect_list , а затем присоединиться к созданному списку:

from pyspark.sql import functions as F
from pyspark.sql.types import StringType
join_ = F.udf(lambda x: ", ".join(x), StringType())
df.groupBy("username").agg(join_(F.collect_list("friend").alias("friends"))
2
ответ дан ksindi 24 August 2018 в 20:58
поделиться

Вот функция, которую вы можете использовать в PySpark:

import pyspark.sql.functions as F

def group_concat(col, distinct=False, sep=','):
    if distinct:
        collect = F.collect_set(col.cast(StringType()))
    else:
        collect = F.collect_list(col.cast(StringType()))
    return F.concat_ws(sep, collect)


table.groupby('username').agg(F.group_concat('friends').alias('friends'))

В SQL:

select username, concat_ws(',', collect_list(friends)) as friends
from table
group by username
2
ответ дан rikturr 24 August 2018 в 20:58
поделиться
Другие вопросы по тегам:

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