Можно ли изменить argv или мне нужно создать настроенную копию?

Использование join (в случае связей это приведет к более чем одной строке в группе):

import pyspark.sql.functions as F
from pyspark.sql.functions import count, col 

cnts = df.groupBy("id_sa", "id_sb").agg(count("*").alias("cnt")).alias("cnts")
maxs = cnts.groupBy("id_sa").agg(F.max("cnt").alias("mx")).alias("maxs")

cnts.join(maxs, 
  (col("cnt") == col("mx")) & (col("cnts.id_sa") == col("maxs.id_sa"))
).select(col("cnts.id_sa"), col("cnts.id_sb"))

Использование оконных функций (приведет к удалению связей):

from pyspark.sql.functions import row_number
from pyspark.sql.window import Window

w = Window().partitionBy("id_sa").orderBy(col("cnt").desc())

(cnts
  .withColumn("rn", row_number().over(w))
  .where(col("rn") == 1)
  .select("id_sa", "id_sb"))

Использование порядка struct:

from pyspark.sql.functions import struct

(cnts
  .groupBy("id_sa")
  .agg(F.max(struct(col("cnt"), col("id_sb"))).alias("max"))
  .select(col("id_sa"), col("max.id_sb")))

См. также Как выбрать первую строку каждой группы?

29
задан ojblass 8 June 2009 в 05:14
поделиться

8 ответов

После того, как argv был передан в метод main, вы можете обращаться с ним как с любым другим массивом C - меняйте его по своему усмотрению, просто помните, что вы делаете с ним. Содержимое массива не влияет на код возврата или выполнение программы, кроме того, что вы явно делаете с ним в коде. Я не могу придумать причину, по которой было бы «нецелесообразно» относиться к этому особо.

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

24
ответ дан Tim 8 June 2009 в 05:14
поделиться

Стандарт C99 говорит об изменении argvargc):

Параметры argc и argv и строки, на которые указывает массив argv, должны изменяться программой, и сохраните их последние сохраненные значения между запуском программы и завершением программы.

67
ответ дан Michael Burr 8 June 2009 в 05:14
поделиться

Единственный раз, когда я бы сказал, что прямое манипулирование argv - это плохая идея, это когда приложение меняет свое поведение в зависимости от содержимого argv [0].

Однако, изменение поведения программы в зависимости от argv [0] само по себе является очень плохой идеей , где переносимость является проблемой.

Кроме этого, вы можете обращаться с ним так же, как с любым другим массивом. Как сказал Джонатан, GNU getopt () неразрушающе переставляет список аргументов, я видел другие реализации getopt (), которые вплоть до сериализации и даже хэширования аргументов (полезны, когда программа приближается к ARG_MAX).

Просто будьте осторожны с арифметикой указателя.

1
ответ дан Tim Post 8 June 2009 в 05:14
поделиться

Некоторые библиотеки делают это!

Метод инициализации, предоставляемый библиотекой glut opengl (GlutInit) , сканирует аргументы, связанные с перенасыщением, и очищает их, перемещая последующие элементы в argv вперед (перемещение указателей, а не фактических строк) и уменьшение argc

2.1

glutInit glutInit используется для инициализации библиотеки GLUT.

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

void glutInit (int * argcp, char ** argv);

argcp

Указатель на неизмененную переменную argc программы из main. По возвращении значение, на которое указывает argcp, будет обновлено, поскольку glutInit извлекает все параметры командной строки, предназначенные для библиотеки GLUT.

argv

Немодифицированная переменная argv программы из main. Как и argcp, данные для argv будут обновлены, поскольку glutInit извлекает любые параметры командной строки, понятные библиотеке GLUT.

1
ответ дан Lanting 8 June 2009 в 05:14
поделиться

В последнем проекте стандарта C (N1256) говорится, что есть две допустимые формы функции main:

int main (void);
int main (int argc, char* argv[]);

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

Некоторые люди специально используют "const char *" для argv, чтобы запретить изменения в аргументах. Если ваша основная функция определена таким образом, вам не разрешено изменять символы, на которые указывает argv[], о чем свидетельствует следующая программа:

pax> cat qq.c
#include <stdio.h>
int main (int c, const char *v[]) {
    *v[1] = 'X';
    printf ("[%s]\n", v[1]);
    return 0;
}

pax> gcc -o qq qq.c
qq.c: In function `main':
qq.c:3: error: assignment of read-only location

Однако, если вы удалите "const", это работает нормально:

pax> cat qq2.c
#include <stdio.h>
int main (int c, char *v[]) {
    *v[1] = 'X';
    printf ("[%s]\n", v[1]);
    return 0;
}

pax> gcc -o qq2 qq2.c ; ./qq2
[Xello]

Я думаю, что это также относится и к C ++. Текущий проект гласит:

All implementations shall allow both of the following definitions of main:
    int main();
    int main(int argc, char* argv[]);

, но он конкретно не запрещает другие варианты, так что вы можете предположительно принять версию "const" в C ++ (и, фактически, g ++ это делает).

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

6
ответ дан paxdiablo 8 June 2009 в 05:14
поделиться

Эмпирически, такие функции, как GNU getopt (), переставляют список аргументов, не вызывая проблем. Как говорит @Tim, пока вы играете разумно, вы можете манипулировать массивом указателей и даже отдельными строками. Только не превышайте ни одну из неявных границ массива.

4
ответ дан Jonathan Leffler 8 June 2009 в 05:14
поделиться

Операционная система помещает argv и argc в стек приложения перед его выполнением, и вы можете обращаться с ними как с любыми другими переменными стека.

2
ответ дан ZelluX 8 June 2009 в 05:14
поделиться

Первоначальное распределение argv оставлено на усмотрение компилятора / среды выполнения. Так что может небезопасно изменять его волей-неволей. Многие системы строят его в стеке, поэтому он автоматически освобождается при возвращении main. Другие строят его в куче и освобождают (или нет), когда main возвращается.

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

Чтобы удалить аргументов, которые вы предварительно обработали , будет работать что-то вроде этого:

(множество условий ошибок не проверено, «--special», другие что первый аргумент не проверен и т. д. Это, в конце концов, просто демонстрационная концепция.)

int main(int argc, char** argv)
{
    bool doSpecial = false; // an assumption
    if (0 == strcmp(argv[1], "--special"))
    {
        doSpecial = true; // no longer an assumption
        // remove the "--special" argument
        //  but do copy the NULL at the end.
        for(int i=1; i<argc; ++i)
            argv[i]  = argv[i+1];
        --argc;
    }
    // all normal processing with "--special" removed.
    // the doSpecial flag is available if wanted.
    return 0;
}

Но посмотрите на это для полной манипуляции: (часть libiberty библиотека, которая используется для управления векторами стиля argv)

http://www.opensource.apple.com/source/gcc/gcc-5666.3/libiberty/argv.c

Это лицензированный GNU LGPL.

0
ответ дан Jesse Chisholm 8 June 2009 в 05:14
поделиться
Другие вопросы по тегам:

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