Ro'yxatdagi har bir noyob qiymatga raqamni belgilang

Menda strings ro'yxati bor. Har bir mag'lubiyatga noyob raqamni tayinlashni istayman (aniq raqam muhim emas) va ushbu raqamlarni qo'llagan holda bir xil uzunlikdagi ro'yxat tuzing. Quyida mening eng yaxshi tashabbusim, lekin men ikki sababdan baxtiyorman:

  1. Xuddi shu qiymatlar bir-birining yonida bo'lishini taxmin qilmoqda

  2. Ro'yxatni 0 bilan boshlashim kerak edi, aks holda chiqdi noto'g'ri bo'ladi

Mening kodim:

names = ['ll', 'll', 'll', 'hl', 'hl', 'hl', 'LL', 'LL', 'LL', 'HL', 'HL', 'HL']
numbers = [0]
num = 0
for item in range(len(names)):
    if item == len(names) - 1:
      break
    elif names[item] == names[item+1]:
        numbers.append(num)
    else:
        num = num + 1
        numbers.append(num)
print(numbers)

Kodni yanada kengroq qilishni istayman, shuning uchun noma'lum ro'yxat bilan ishlaydi. Har qanday fikr bormi?

11
algoritmni qo'llashdan oldin ro'yxatni tartiblash haqida
qo'shib qo'ydi muallif Piotr Kamoda, manba

8 javoblar

Tashqi kutubxonadan foydalanmasdan ( Pandas echim uchun EDIT ni tekshiring) buni quyidagi kabi bajarishingiz mumkin:

d = {ni: indi for indi, ni in enumerate(set(names))}
numbers = [d[ni] for ni in names]

Qisqacha izoh:

Birinchi satrda siz ro'yxatidagi har bir noyob elementga raqamni tayinlaysiz (lug'atda saqlanadigan d , siz uni lug'at tushunchasini osongina yaratishingiz mumkin; set nomlari noyob elementlari).

Keyin, ikkinchi qatorda siz ro'yxatni tushunishingiz va haqiqiy raqamlarni numbers ro'yxatida saqlaysiz.

Buning o'rnakiga ko'ra, bu tartib-qoida ro'yxatlari uchun ham yaxshi ishlaydi:

# 'll' appears all over the place
names = ['ll', 'll', 'hl', 'hl', 'hl', 'LL', 'LL', 'll', 'LL', 'HL', 'HL', 'HL', 'll']

Bu numbers uchun chiqish:

[1, 1, 3, 3, 3, 2, 2, 1, 2, 0, 0, 0, 1]

Ko'rib turganingizdek, ll bilan bog'langan 1 raqamlari to'g'ri joylarda paydo bo'ladi.

EDIT -ni tanlang

If you have Pandas available, you can also use pandas.factorize (which seems to be quite efficient for huge lists and also works fine for lists of tuples as explained here):

import pandas as pd

pd.factorize(names)

keyin qaytib keladi

(array([(array([0, 0, 1, 1, 1, 2, 2, 0, 2, 3, 3, 3, 0]),
 array(['ll', 'hl', 'LL', 'HL'], dtype=object))

Shuning uchun,

numbers = pd.factorize(names)[0]
13
qo'shib qo'ydi

Agar shartlar raqamlar noyob va aniq raqam muhim bo'lmasa bo'lsa, ro'yxatdagi har bir narsaga tegishli xaritalashni noyob raqamga aylantirib, hisoblash obyektidan qiymatlarni belgilashingiz mumkin :

from itertools import count

names = ['ll', 'll', 'hl', 'hl', 'LL', 'LL', 'LL', 'HL', 'll']

d = {}
c = count()
numbers = [d.setdefault(i, next(c)) for i in names]
print(numbers)
# [0, 0, 2, 2, 4, 4, 4, 7, 0]

map dan foydalanib, qo'shimcha nomlarni o'chirishingiz mumkin. ro'yxatida va hisoblash obyektida va kod funksiyasini {} .setdefault sifatida belgilab qo'ying (@ StefanPochmannning sharhini ko'ring):

from itertools import count

names = ['ll', 'll', 'hl', 'hl', 'LL', 'LL', 'LL', 'HL', 'll']
numbers  = map({}.setdefault, names, count()) # call list() on map for Py3
print(numbers)
# [0, 0, 2, 2, 4, 4, 4, 7, 0]

Qo'shimcha sifatida, siz ham np.unique , agar sizda numpy o'rnatilgan bo'lsa:

import numpy as np

_, numbers = np.unique(names, return_inverse=True)
print(numbers)
# [3 3 2 2 1 1 1 0 3]
6
qo'shib qo'ydi
Agar siz ro'yxati (map ({} (set}, setdefault, nomlar, count ())) ni ishlatsangiz, qo'shimcha parametrlarga ehtiyoj yo'q.
qo'shib qo'ydi muallif Stefan Pochmann, manba
Birinchi hal qilishda Keyingi (s) o'rniga len (d) dan foydalanishingiz mumkin: a = la = (d.setdefault (i, len (d) ) i uchun nomlar]
qo'shib qo'ydi muallif RootTwo, manba
@StefanPochmann Juda chiroyli!
qo'shib qo'ydi muallif Moses Koledoye, manba

Keyinchalik umumiy funktsiyani bajarish uchun siz uni funktsiyaga ulashingiz mumkin, shuning uchun bu qattiq kodlangan qiymatlar hech qanday zarar qilmaydi, chunki ular mahalliydir.

Agar siz samarali qidirish-konteynerlardan foydalansangiz (aniq lug'at foydalansam), siz har bir mag'lubiyatning birinchi ko'rsatkichini juda ko'p ishlashga mahrum qilmasdan ushlab turishingiz mumkin:

def your_function(list_of_strings):

    encountered_strings = {}
    result = []

    idx = 0
    for astring in list_of_strings:
        if astring in encountered_strings:  # check if you already seen this string
            result.append(encountered_strings[astring])
        else:
            encountered_strings[astring] = idx
            result.append(idx)
            idx += 1
    return result

Va bu indekslarni tartibga soladi (agar bu muhim bo'lmasa ham):

>>> your_function(['ll', 'll', 'll', 'hl', 'hl', 'hl', 'LL', 'LL', 'LL', 'HL', 'HL', 'HL'])
[0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3]

Bu sizning tizzangiz ro'yxatida faqat bitta iteratsiya kerak, bu esa jeneratörlarni va shunga o'xshash narsalarni ishlashga imkon beradi.

3
qo'shib qo'ydi

Agar sizda k turli qiymatlar mavjud bo'lsa, bu ularni k k-1 ga birinchi marta keladigan tartibda aniqlaydi:

>>> names = ['b', 'c', 'd', 'c', 'b', 'a', 'b']
>>> tmp = {}
>>> [tmp.setdefault(name, len(tmp)) for name in names]
[0, 1, 2, 1, 0, 3, 0]
3
qo'shib qo'ydi

Sizning skriptingizni biroz o'zgartirib yubordim va OK ko'rinadi:

names = ['ll', 'hl', 'll', 'hl', 'LL', 'll', 'LL', 'HL', 'hl', 'HL', 'LL', 'HL', 'zzz']
names.sort()
print(names)
numbers = []
num = 0
for item in range(len(names)):
    if item == len(names) - 1:
      break
    elif names[item] == names[item+1]:
        numbers.append(num)
    else:
        numbers.append(num)
        num = num + 1
numbers.append(num)
print(numbers)

Ko'rinib turibdiki, bu juda simmilar, faqatgina NEXT elementiga raqam qo'shish o'rniga, CURRENT elementi uchun raqam qo'shiladi. Hammasi shu. Oh, va tartiblash. Birinchi navbatda sarmoyani tartibga keltiradi, keyin esa bu misolda kichik harfni o'zgartiradi, agar siz buni o'zgartirmoqchi bo'lsangiz sort (key = lambda: x ...) bilan o'ynang. (Ehtimol, shunga o'xshash: names.sort (key = lambda x: (x.lower() == x if x.lower ()) x.upper () )

2
qo'shib qo'ydi

Buni ham sinashingiz mumkin: -

names = ['ll', 'll', 'll', 'hl', 'hl', 'hl', 'LL', 'LL', 'LL', 'HL', 'HL', 'HL']

indexList = list(set(names))

print map(lambda name:indexList.index(name),names)
1
qo'shib qo'ydi
Lambda ichida indexList.index o'ramining nimasi?
qo'shib qo'ydi muallif Stefan Pochmann, manba
@StefanPochmann, ha, bu xaritani ham yozishingiz mumkin (indexList.index, nomlari), agar siz lambda
qo'shib qo'ydi muallif Rakesh Kumar, manba

Siz strings tamsayılar xaritasi qilganingizdan beri, bu dictdan foydalanishni taklif qiladi. Shunday qilib, quyidagilarni qilishingiz mumkin:

d = dict()

counter = 0

for name in names:
    if name in d:
        continue
    d[name] = counter
    counter += 1

numbers = [d[name] for name in names]
0
qo'shib qo'ydi
Tepaga tushgan, tushuntirishga e'tibor beraymi?
qo'shib qo'ydi muallif Nir Friedman, manba

Mana shunga o'xshash factorizing echimini < kodi> collections.defaultdict va itertools.count :

import itertools as it
import collections as ct


names = ['ll', 'll', 'hl', 'hl', 'LL', 'LL', 'LL', 'HL', 'll']

dd = ct.defaultdict(it.count().__next__)
[dd[i] for i in names]
# [0, 0, 1, 1, 2, 2, 2, 3, 0]

Har bir yangi voqea keyingi tamsayıni itertools.count deb chaqiradi va dd ga yangi kirish qo'shimchalar.

0
qo'shib qo'ydi
Python
Python
372 ishtirokchilar

Bu guruh python dasturlash tilini muhokama qilish uchun. Iltimos, o'zingizni hurmat qiling va faqat dasturlash bo'yicha yozing. Botlar mavzusini @botlarhaqida guruhida muhokama qling! FAQ: @PyFAQ Offtopic: @python_uz_offtopic

Python offtopic group !
Python offtopic group !
150 ishtirokchilar

@python_uz gruppasining offtop gruppasi. offtop bo'lsa ham reklama mumkin emas ) Boshqa dasturlash tiliga oid gruppalar @languages_programming