Considere as três listas de exemplos a seguir:
List<string> localPatientsIDs = new List<string> { "1550615", "1688", "1760654", "1940629", "34277", "48083" };
List<string> remotePatientsIDs = new List<string> { "000-007", "002443", "002446", "214", "34277", "48083" };
List<string> archivedFiles = new List<string>{
@"G:\Archive\000-007_20230526175817297.zip",
@"G:\Archive\002443_20230526183639562.zip",
@"G:\Archive\002446_20230526183334407.zip",
@"G:\Archive\14967_20240703150011899.zip",
@"G:\Archive\214_20231213150003676.zip",
@"G:\Archive\34277_20230526200048891.zip",
@"G:\Archive\48083_20240214150011919.zip" };
Observe que cada elemento em archivedFiles
é o caminho completo de um arquivo ZIP, cujo nome começa com o patientID
que está em localPatientsIDs
ou remotePatientsIDs
.
Por exemplo: @"G:\Archive\000-007_20230526175817297.zip"
: o nome do arquivo 000-007_20230526175817297.zip
inicia com 000-007
, que é um elemento na lista remotePatientsIDs
.
Um patientID não pode estar em localPatientsIDs
e archivedFiles
simultaneamente, portanto, nenhuma duplicata é permitida entre essas duas listas. No entanto, o archivedFiles
pode conter patientIDs que também estão localizados em remotePatientsIDs
.
Preciso obter os elementos em archivedFiles
cujos nomes de arquivo começam com os elementos presentes em remotePatientsIDs
mas não presentes em localPatientsIDs
. O ponto final é descompactar esses arquivos para o diretório que contém localPatientsIDs
o banco de dados.
Para o exemplo dado, eu esperaria ter o seguinte resultado:
archivedFilesToUnzip == {
@"G:\Archive\000-007_20230526175817297.zip",
@"G:\Archive\002443_20230526183639562.zip",
@"G:\Archive\002446_20230526183334407.zip",
@"G:\Archive\214_20231213150003676.zip" }
Então, como posso usar o LINQ para fazer isso?
Na minha falta de conhecimento, eu esperaria que fosse tão simples quanto:
List<string> archivedFilesToUnzip = archivedFiles.Where(name => name.Contains(remotePatients.Except(localPatients)))
Não consigo nem compilar isso, pois Contains
provavelmente não consigo iterar sobre os membros da lista e recebo a mensagem:
CS1503: Argument 1: cannot convert from 'System.Collections.Generic.IEnumerable<string>' to 'string'
Então meu melhor teste até agora é a seguinte frase (confesso que parece um pouco confusa para mim). Ela sempre retorna uma lista vazia.
List<string> archivedFilesToUnzip = archivedFiles.Where(name => archivedFiles.Any(x => x.ToString().Contains(remotePatients.Except(localPatients).ToString()))).ToList();
Encontrei estas postagens úteis que me ajudaram a entender melhor as diferenças entre Where
e Select
:
Além disso, estou procurando instruções sobre como usar LINQ em:
- Filtrar lista com outra lista usando LINQ
- Filtrar uma lista por outra lista C#
- Filtrar uma lista com base em outra condição de lista
e outros links também, mas ainda não consigo encontrar uma solução que funcione.
C# é uma linguagem estaticamente (e principalmente fortemente) tipada (veja a pergunta Qual é a diferença entre uma linguagem fortemente tipada e uma linguagem estaticamente tipada? e o artigo O sistema de tipos C# se quiser se aprofundar mais). Isso significa que o compilador verificará os tipos de variáveis e não permitirá muitos erros, como comparar string e boolean.
remotePatients.Except(localPatients)
é uma coleção destring
's enquantoname
emarchivedFiles.Where(name => name
é "apenas" umstring
.Contains
em uma string pode aceitarchar
(um símbolo em astring
) ou outrostring
, não uma coleção de strings, daí o erro de compilação.Sua segunda tentativa compila, mas não produzirá nada significativo - se você atribuir
remotePatients.Except(localPatients).ToString()
a uma variável e examiná-la ou imprimir o resultado no console, verá apenas o nome do tipo (System.Linq.Enumerable+<ExceptIterator>d__99
1[System.String]` para ser exato), que obviamente não faz parte do nome do arquivo.Quanto à sua pergunta, eu sugeriria fazer o seguinte:
Isso usa uma expressão regular para extrair o id do nome do arquivo e então pesquisá-lo nos ids "ausentes".
Uma explicação para essa expressão regular específica pode ser encontrada em @regex101 .
Aqui está uma consulta LINQ simples fazendo o que você quer:
Aqui vai um pequeno resumo:
localPatientsIDs.Any(Path.GetFileName(file).StartsWith)
verificará se há algum item noslocalPatientsIDs
critérios correspondentes, que são:Path.GetFileName(file).StartsWith
-Path.GetFileName
obterá o nome do arquivo do caminho,StartsWith
verificará se o nome do arquivo começa com algum elemento delocalPatientsIDs
Para deixar mais claro, eu definiria tal método:
e então você pode usá-lo assim:
ATUALIZAR
Se você quiser ver se o nome do arquivo começa com o prefixo definido seguido por
_
, use este código:e método modificado:
Você pode tentar esta consulta LINQ, que retorna o resultado esperado: