UPDATE: Спасибо всем за все, что угодно, но я не думаю, что мой ответ ниже - лучший способ написать перечисления в Javascript. См. Мой блог для более подробной информации: Перечисления в Javascript .
Предупреждение о названии уже возможно:
if (currentColor == my.namespace.ColorEnum.RED) {
// alert name of currentColor (RED: 0)
var col = my.namespace.ColorEnum;
for (var name in col) {
if (col[name] == col.RED)
alert(name);
}
}
Кроме того, вы могли бы сделайте объекты значений, чтобы вы могли получить торт и съесть его:
var SIZE = {
SMALL : {value: 0, name: "Small", code: "S"},
MEDIUM: {value: 1, name: "Medium", code: "M"},
LARGE : {value: 2, name: "Large", code: "L"}
};
var currentSize = SIZE.MEDIUM;
if (currentSize == SIZE.MEDIUM) {
// this alerts: "1: Medium"
alert(currentSize.value + ": " + currentSize.name);
}
В Javascript, так как это динамический язык, возможно даже добавить значения перечисления в набор позже:
// Add EXTRALARGE size
SIZE.EXTRALARGE = {value: 3, name: "Extra Large", code: "XL"};
Помните, что поля перечисления (значение, имя и код в этом примере) не нужны для проверки подлинности и доступны только для удобства. Также имя самого свойства size не обязательно должно быть жестко запрограммировано, но также может быть установлено динамически. Предположим, что вы знаете только имя для нового значения enum, вы можете добавить его без проблем:
// Add 'Extra Large' size, only knowing it's name
var name = "Extra Large";
SIZE[name] = {value: -1, name: name, code: "?"};
Конечно, это означает, что некоторые предположения больше не могут быть сделаны (это значение представляет правильный порядок для размера, например).
Помните, что в Javascript объект похож на карту или хеш-таблицу. Набор пар имя-значение.
EG:
for (var sz in SIZE) {
// sz will be the names of the objects in SIZE, so
// 'SMALL', 'MEDIUM', 'LARGE', 'EXTRALARGE'
var size = SIZE[sz]; // Get the object mapped to the name in sz
for (var prop in size) {
// Get all the properties of the size object, iterates over
// 'value', 'name' and 'code'. You can inspect everything this way.
}
}
И, кстати, если вы заинтересованы в пространствах имен, вы можете захотеть взгляните на мое решение для простого, но мощного управления пространством имен и зависимостей для javascript: Пакеты JS
Подобно предложению @locojay, вы можете применить difflib
's get_closest_matches
к индексу df2
, а затем применить join
:
In [23]: import difflib
In [24]: difflib.get_close_matches
Out[24]: <function difflib.get_close_matches>
In [25]: df2.index = df2.index.map(lambda x: difflib.get_close_matches(x, df1.index)[0])
In [26]: df2
Out[26]:
letter
one a
two b
three c
four d
five e
In [31]: df1.join(df2)
Out[31]:
number letter
one 1 a
two 2 b
three 3 c
four 4 d
five 5 e
.
Если это были столбцы, в том же духе вы могли бы применить к столбцу, тогда merge
:
df1 = DataFrame([[1,'one'],[2,'two'],[3,'three'],[4,'four'],[5,'five']], columns=['number', 'name'])
df2 = DataFrame([['a','one'],['b','too'],['c','three'],['d','fours'],['e','five']], columns=['letter', 'name'])
df2['name'] = df2['name'].apply(lambda x: difflib.get_close_matches(x, df1['name'])[0])
df1.merge(df2)
Вы можете использовать d6tjoin для этого
import d6tjocin.top1
d6tjoin.top1.MergeTop1(df1.reset_index(),df2.reset_index(),
fuzzy_left_on=['index'],fuzzy_right_on=['index']).merge()['merged']
index number index_right letter
0 one 1 one a
1 two 2 too b
2 three 3 three c
3 four 4 fours d
4 five 5 five e
Он имеет множество дополнительных функций, таких как:
http://pandas.pydata.org/pandas-docs/dev/merging.html не имеет функции hook для этого на лету. Было бы неплохо, хотя ...
Я бы просто сделал отдельный шаг и использовал difflib getclosest_matches, чтобы создать новый столбец в одном из двух фреймов данных и слияние / объединение на нечетком совпадающем столбце
Я бы использовал Jaro-Winkler, потому что это один из наиболее эффективных и точных приближенных алгоритмов сопоставления строк, доступных в настоящее время [ Cohen, et al. ], [ Winkler ].
Так я сделал бы это с Jaro-Winkler из пакета медузы :
def get_closest_match(x, list_strings):
best_match = None
highest_jw = 0
for current_string in list_strings:
current_score = jellyfish.jaro_winkler(x, current_string)
if(current_score > highest_jw):
highest_jw = current_score
best_match = current_string
return best_match
df1 = pandas.DataFrame([[1],[2],[3],[4],[5]], index=['one','two','three','four','five'], columns=['number'])
df2 = pandas.DataFrame([['a'],['b'],['c'],['d'],['e']], index=['one','too','three','fours','five'], columns=['letter'])
df2.index = df2.index.map(lambda x: get_closest_match(x, df1.index))
df1.join(df2)
Выход:
number letter
one 1 a
two 2 b
three 3 c
four 4 d
five 5 e
Как хэдз-ап, это в основном работает, за исключением случаев, когда совпадение не найдено, или если у вас есть NaNs в любом столбце. Вместо прямого применения get_close_matches
мне было проще применить следующую функцию. Выбор заменителей NaN будет сильно зависеть от вашего набора данных.
def fuzzy_match(a, b):
left = '1' if pd.isnull(a) else a
right = b.fillna('2')
out = difflib.get_close_matches(left, right)
return out[0] if out else np.NaN
Я написал пакет Python, целью которого является решение этой проблемы:
pip install fuzzymatcher
Здесь вы можете найти repo здесь и docs здесь .
Базовое использование:
Для двух фреймов данных df_left
и df_right
, которые вы хотите использовать нечеткое соединение, вы можете написать следующее:
from fuzzymatcher import link_table, left join
# Columns to match on from df_left
left_on = ["fname", "mname", "lname", "dob"]
# Columns to match on from df_right
right_on = ["name", "middlename", "surname", "date"]
# The link table potentially contains several matches for each record
fuzzymatcher.link_table(df_left, df_right, left_on, right_on)
Или если вы просто хотите установить ссылку в ближайшем совпадении:
fuzzymatcher.fuzzy_left_join(df_left, df_right, left_on, right_on)