Фильтрация списков, содержащих строковый шаблон - PullRequest
0 голосов
/ 17 сентября 2018

Мне нужно отфильтровать элементы в списке, содержащем строку Status = ACTIVE и сохранить его как новый список.

Позже мне также нужно отфильтровать тот же список с помощью Status = STOPPED и Система = Windows .

Список:

Programs=
    ["Process=1,System=Linux,PID=240,Program=DRMX,Status=ACTIVE",
    "Process=1,System=Linux,PID=240,Program=DRMX,Status=STOPPED",
    "Process=1,System=Windows,PID=240,Program=DRMX,Status=ACTIVE",
    "Process=1,System=Linux,PID=242,Program=DRMX,Status=ACTIVE",
    "Process=1,System=Windows,PID=242,Program=DRMX,Status=STOPPED",
    "Process=1,System=Windows,PID=242,Program=DRMX,Status=ACTIVE",
    "Process=1,System=Linux,PID=246,Program=DRMX,Status=ACTIVE",
    "Process=1,System=Linux,PID=246,Program=DRMX,Status=STOPPED",
    "Process=1,System=Linux,PID=246,Program=DRMX,Status=ACTIVE"].

Требуемый результат:

["Process=1,System=Linux,PID=240,Program=DRMX,Status=ACTIVE",
    "Process=1,System=Windows,PID=240,Program=DRMX,Status=ACTIVE",
    "Process=1,System=Linux,PID=242,Program=DRMX,Status=ACTIVE",
    "Process=1,System=Windows,PID=242,Program=DRMX,Status=ACTIVE",
    "Process=1,System=Linux,PID=246,Program=DRMX,Status=ACTIVE",
    "Process=1,System=Linux,PID=246,Program=DRMX,Status=ACTIVE"].

и:

["Process=1,System=Windows,PID=242,Program=DRMX,Status=STOPPED"].

Я нашел возможное решение отфильтровать его с помощью re: run / 2 и lists: filter / 2.Есть ли более простой и быстрый способ?

Filter=fun(Acc)->
    nomatch =/= re:run(Acc,"Status=ACTIVE") end.
Result=lists:filter(Filter,Programs).

Br,

Damian

Ответы [ 4 ]

0 голосов
/ 19 сентября 2018

Хотя choroba ' решение совершенно правильно, я бы немного написал о лучших практиках Erlang. Одной из очень хороших практик является преобразование данных извне мира Эрланга как можно скорее в соответствующие структуры Эрланга. Это окупится в долгосрочном развитии и обслуживании проекта, когда проект будет расти и становиться более сложным, требовать правильных операций, отладки, устранения неполадок и т. Д. Поэтому вы обычно анализируете как можно больше текстовых данных для записей, атомов, целых чисел. , цифры и т. д. Это позволяет две вещи. Во-первых, вы проверяете входящие данные как можно скорее, и вы будете предотвращать распространение ошибок внутри вашей системы на границе. Который затем позволяет использовать быстрый подход. Во-вторых, вы можете написать множество вспомогательных функций, что значительно облегчает дальнейшее развитие. Что-то вроде

-module(programs).

-record(program, {
          process,
          system,
          pid,
          program,
          status
         }).

%% API

-export([parse_programs/1, active/1, stopped/1, linux/1, windows/1]).

parse_programs(L) ->
    [parse_program(X) || X <- L].

active(P) -> P#program.status =:= active.

stopped(P) -> P#program.status =:= stopped.

linux(P) -> P#program.system =:= 'Linux'.

windows(P) -> P#program.system =:= 'Windows'.

%% Internal functions

parse_program(Str) ->
    parse_program(string:tokens(Str, ","), #program{}).

parse_program([], P) -> P;
parse_program(["Process=" ++ Str | T], P) ->
    parse_program(T, P#program{process = list_to_integer(Str)});
parse_program(["System=" ++ Str | T], P) ->
    parse_program(T, P#program{system = parse_system(Str)});
parse_program(["PID=" ++ Str | T], P) ->
    parse_program(T, P#program{pid = list_to_integer(Str)});
parse_program(["Program=" ++ Str | T], P) ->
    parse_program(T, P#program{program = Str});
parse_program(["Status=" ++ Str | T], P) ->
    parse_program(T, P#program{status = parse_status(Str)});
parse_program([H | _], _) ->
    error(badarg, [H]).

parse_system("Linux") -> 'Linux';
parse_system("Windows") -> 'Windows';
parse_system(Str) -> error(badarg, [Str]).

parse_status("ACTIVE") -> active;
parse_status("STOPPED") -> stopped;
parse_status(Str) -> error(badarg, [Str]).

Тогда дальнейшие задачи становятся легкими

1> c(programs).
{ok,programs}
2> rr("programs.erl").
[program]
3> Programs=
3>     ["Process=1,System=Linux,PID=240,Program=DRMX,Status=ACTIVE",
3>     "Process=1,System=Linux,PID=240,Program=DRMX,Status=STOPPED",
3>     "Process=1,System=Windows,PID=240,Program=DRMX,Status=ACTIVE",
3>     "Process=1,System=Linux,PID=242,Program=DRMX,Status=ACTIVE",
3>     "Process=1,System=Windows,PID=242,Program=DRMX,Status=STOPPED",
3>     "Process=1,System=Windows,PID=242,Program=DRMX,Status=ACTIVE",
3>     "Process=1,System=Linux,PID=246,Program=DRMX,Status=ACTIVE",
3>     "Process=1,System=Linux,PID=246,Program=DRMX,Status=STOPPED",
3>     "Process=1,System=Linux,PID=246,Program=DRMX,Status=ACTIVE"].
["Process=1,System=Linux,PID=240,Program=DRMX,Status=ACTIVE",
 "Process=1,System=Linux,PID=240,Program=DRMX,Status=STOPPED",
 "Process=1,System=Windows,PID=240,Program=DRMX,Status=ACTIVE",
 "Process=1,System=Linux,PID=242,Program=DRMX,Status=ACTIVE",
 "Process=1,System=Windows,PID=242,Program=DRMX,Status=STOPPED",
 "Process=1,System=Windows,PID=242,Program=DRMX,Status=ACTIVE",
 "Process=1,System=Linux,PID=246,Program=DRMX,Status=ACTIVE",
 "Process=1,System=Linux,PID=246,Program=DRMX,Status=STOPPED",
 "Process=1,System=Linux,PID=246,Program=DRMX,Status=ACTIVE"]
4> Ps = programs:parse_programs(Programs).
[#program{process = 1,system = 'Linux',pid = 240,
          program = "DRMX",status = active},
 #program{process = 1,system = 'Linux',pid = 240,
          program = "DRMX",status = stopped},
 #program{process = 1,system = 'Windows',pid = 240,
          program = "DRMX",status = active},
 #program{process = 1,system = 'Linux',pid = 242,
          program = "DRMX",status = active},
 #program{process = 1,system = 'Windows',pid = 242,
          program = "DRMX",status = stopped},
 #program{process = 1,system = 'Windows',pid = 242, 
          program = "DRMX",status = active},
 #program{process = 1,system = 'Linux',pid = 246,
          program = "DRMX",status = active},
 #program{process = 1,system = 'Linux',pid = 246,
          program = "DRMX",status = stopped},
 #program{process = 1,system = 'Linux',pid = 246,
          program = "DRMX",status = active}]
5> lists:filter(fun programs:active/1, Ps).
[#program{process = 1,system = 'Linux',pid = 240,
          program = "DRMX",status = active},
 #program{process = 1,system = 'Windows',pid = 240,
          program = "DRMX",status = active},
 #program{process = 1,system = 'Linux',pid = 242,
          program = "DRMX",status = active},
 #program{process = 1,system = 'Windows',pid = 242,
          program = "DRMX",status = active},
 #program{process = 1,system = 'Linux',pid = 246,
          program = "DRMX",status = active},
 #program{process = 1,system = 'Linux',pid = 246,
          program = "DRMX",status = active}]
6> lists:filter(fun(P) -> programs:stopped(P) andalso programs:windows(P) end, Ps).
[#program{process = 1,system = 'Windows',pid = 242,
          program = "DRMX",status = stopped}]

В качестве побочного эффекта ваша программа будет потреблять намного меньше памяти, поскольку и числа, и атомы потребляют намного меньше, чем строки. И любая дальнейшая обработка будет намного быстрее, потому что сравнение всех атомов такое же, как сравнение чисел, и чем меньше памяти, тем больше данных в кэше ЦП и попадание в кэш ЦП почти на два порядка быстрее, чем доступ к основной памяти.

В этом случае

7> erts_debug:size(Programs).                                         
1062
8> erts_debug:size(Ps).      
153

Это означает, что вы можете поместить почти в семь раз больше данных в кеш вашего процессора. Когда вы отправляете сообщения между процессами или узлами в распределении Erlang, это будет в семь раз быстрее, ... (Если бы вы использовали list_to_binary / 1 для имени программы, это было бы даже в десять раз больше).

parse_program(["Program=" ++ Str | T], P) ->
    parse_program(T, P#program{program = list_to_binary(Str)});

тогда

9> c(programs).
{ok,programs}
10> f(Ps).
ok
11> Ps = programs:parse_programs(Programs).
[{program,1,'Linux',240,<<"DRMX">>,active},
 {program,1,'Linux',240,<<"DRMX">>,stopped},
 {program,1,'Windows',240,<<"DRMX">>,active},
 {program,1,'Linux',242,<<"DRMX">>,active},
 {program,1,'Windows',242,<<"DRMX">>,stopped},
 {program,1,'Windows',242,<<"DRMX">>,active},
 {program,1,'Linux',246,<<"DRMX">>,active},
 {program,1,'Linux',246,<<"DRMX">>,stopped},
 {program,1,'Linux',246,<<"DRMX">>,active}]
12> erts_debug:size(Ps).
108

Итак, с 8,3 КБ мы до 864 Б.

0 голосов
/ 17 сентября 2018

Я бы настоятельно рекомендовал разбирать такой список на список записей, чтобы формализовать структуру данных. Фильтрация с записью становится очень элегантной:

-record(program,{process,
                 system,
                 pid,
                 program,
                 status}).

% Parse list of strings to list of programs
ParsedPrograms=parseProgram(Programs),
[Valid || Valid = #program{status="STOPPED", system="Windows"} <- ParsedPrograms].
0 голосов
/ 18 сентября 2018

Вы также можете использовать string: str / 2 или string: find / 2, так как str устарел.

ListA = [X || X <- Programs, string:str(X, "ACTIVE") > 0],
ListB = [X || X <- Programs, string:str(X, "STOPPED") > 0 and string:str(X, "Windows") > 0].

ListA = [X || X <- Programs, string:find(X, "ACTIVE") /= undefined],
ListB = [X || X <- Programs, string:find(X, "STOPPED") /= undefined and string:find(X, "Windows") /= undefined]
0 голосов
/ 17 сентября 2018

Первое может быть достигнуто с помощью

lists:filter(
    fun (A) ->
        lists:member("Status=ACTIVE", string:tokens(A,","))
    end, Programs).

, в то время как второе немного сложнее, так как необходимо проверить два условия:

lists:filter(
    fun(A) ->
        Tokens = string:tokens(A, ","),
        lists:member("Status=STOPPED", Tokens)
        andalso lists:member("System=Windows", Tokens)
    end, Programs).

Я неКонечно, это быстрее, но, по крайней мере, гораздо более читабельно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...