OVH Cloud OVH Cloud

comptage de caracteres specifique dans une chaine

22 réponses
Avatar
Eric Deveaud
bonjour,

je dispose de chaines de plusieur centaines de milliers de caracteres
parmis les caracteres de ces chaines certains sont des caracteres de padding
(un seul par type de chaine, généralement c'est le caractere *)

je dois à partir des chaines avec padding sortir les données suivantes

1) une liste des positions (indice) ou apparaissent ces caracteres de padding

2) une liste de la taille de la chaine d'origine avec comme valeur pour chaque
position le nombre de caracteres de padding rencontrés jsuqu'a cette position
incluse

exemple: sur une chaine de 15 de long

0 10 20
| |
padded_seq = "aaaaaa*aaaa*aaa"
^ ^
| |
6 11

je veux obtenir
padding_pos --> [6, 11]
padding_count --> [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2]


pour ce faire j'ai commis les bouts de code suivants


Option 1 je découpe en 2 taches individuelles

#determination des positions des caracteres de padding
def get_padding_pos(padded_str, padding_mark='*'):
res = []
start = 0
p = padded_str.find(padding_mark, start)
while p != -1:
res.append(p)
p = padded_str.find(padding_mark, start)
return res

# determination de la liste du nombre de padding_mark precedent une position
def get_padding_count(padded_str, padding_mark='*'):
padding_count = []
n = 0
start = 0
for end in padding_pos:
padding_count += [n]*(end-start)
start = end
n+=1

padding_count += [n]*(len(padded_seq)-start)

option 2 je fais les 2 d'un coup

def get_padded_spec(padded_seq, padding_mark='*'):
i = n = 0
stop = len(padded_seq)
padding_pos = []
padding_count = []
while i < stop:
if padded_seq[i] == padding_mark:
padding_pos.append(i)
n += 1
padding_count.append(n)
i += 1
return padding_pos, padding_count
je trouve ça très lourd comme traitement surtout sur des chaines de plusieurs
centaines de milliers de caracteres, avez vous mieux à me proposer ??

pour le momment je travaille sur des listes, je vais passer en array très
prochainement, y gagnerais-je en temps d'exécution (je sais j'ai qu'a mesurer)

Eric
--
- mais ce netbsd, c'est un linux ou pas ??
- NON ! C'est un Unix ! C'est un Unix-based et Linux est un Unix-like
- ok c bien ce ke je me disait, bon alors je recherche toujours un LINUX
-+- Dragondir in Guide du BSDiste pervers -+- Vous avez dit Nulix ? -+-

10 réponses

1 2 3
Avatar
erichuchet
effectivement c'est plutot rapide.

De mon coté j'ai testé en comparaison le code de Gerard Flanagan, et
il s'avere 2 a 3x plus rapide que les list comprehension.

eric
Avatar
Eric Deveaud
Méta-MCI wrote:
Re

Par exemple, pour une chaîne de 1,5 millions de caractères, contenant 200
000 marques, cela met 3,6 s sur mon Win-XP à 1,6 GHz.

Maintenant, si l'on veut aller plus vite, il faudrait, AMHA, remplacer
"append" par une initialisation préalable de "l" (dont on connaît la
longueur a priori), avec une affectation indicée.
Mais, est-ce bien nécessaire ?


si je comprends bien, tu proposes une initialisation de la liste puis une
affectation.

OK
pour la génération du nombre de caracteres de padding précédant une position
donnée tu proposerai donc un truc du genre

len_pad = len(padded_seq)
padding_count = [0] * len_pad
i = n =0
for c in padded_seq:
if c == padding_mark:
n+=1
padding_count[i] = n
i +=1


Eric

PS je vais mesurer les temps d'execution des différentes approches et vous
tiendrais au courant.

Avatar
bruno at modulix
Méta-MCI wrote:
Encore plus court :

seq = "aaaaaa*aaaa*aaa"
marq="*"
l=[]
print [p for p,c in enumerate(seq) if l.append(len(locals()['_[1]'])) or
(c==marq)]
print l



Là, chapo.

C'est quoi cet immonde hack avec locals()['_[1]'] ???


--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in ''.split('@')])"

Avatar
bruno at modulix
Philippe Bouige wrote:
(snip)
pour la position celle-ci te va ?


padded_seq = "aaaaaa*aaaa*aaa"
[ index for index in range(len(padded_seq)) if padded_seq[index] == '*']





enumerate() est ton amie:

[index for index, char in enumerate(padded_seq) if char == '*']

[6, 11]


je cherche pour l'autre, Philippe ;-)



--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in ''.split('@')])"




Avatar
Laurent Pointal
Méta-MCI wrote:
Encore plus court :

seq = "aaaaaa*aaaa*aaa"
marq="*"
l=[]
print [p for p,c in enumerate(seq) if l.append(len(locals()['_[1]'])) or
(c==marq)]
print l



Là, chapo.

C'est quoi cet immonde hack avec locals()['_[1]'] ???


Il me semble que _ est le résultat de l'évaluation de l'expression

précédente (ie. pas sûr que ça marche si on le colle dans une fonction).


Avatar
Michel Claveau
'soir !

C'est exact.

locals()['_[1]'] fait référence à la liste en cours de création, dans
une liste en intention. S'il y a plusieurs listes, locals()['_[2]']
fait référence à la suivante, etc.

C'est vrai que c'est immonde (comme un troll). Mais, bon, on peut
programmer salement, en Python aussi...

--
@-salutations

Michel Claveau
Avatar
Bertrand B

print [p for p,c in enumerate(seq) if l.append(len(locals()['_[1]'])) o r
(c==marq)]


clair comme du jus de perl
C'est la puissance du côté obscure qui vous attire

Avatar
MC
'soir !

clair comme du jus de perl




oui, mais,c'est vendredi !
Je rassure : je n'utilise pas ce genre de truc en production...

--
@-salutations

Michel Claveau



Avatar
Méta-MCI
Bonsoir !

Une autre façon de faire, assez rapide :


seq = "aaaaaa*aaaa*aaa"
marq="*"
l=[0]*len(seq) #liste 'compteurs'
lpoi=[] #liste des marques

compteur=-1
for i in seq.split(marq)[:-1]:
compteur+=len(i)+1
lpoi.append(compteur)

j=0
for n,i in enumerate(lpoi):
l[j:i]=[n]*(i-j)
j=i
l[j:]=[n+1]*(len(l)-j)



@+

MCI
Avatar
Méta-MCI
J'ai répondu dans le message à Laulau..
1 2 3