具体例
from openpyxl import load_workbook
org = 'hogeExcel.xlsx'
sheet_name = 'fuga'
sheet_name2 = 'fugafuga'
wb = load_workbook(org)
ws = wb[sheet_name]
ws['C2'] = "=UNIQUE({0}!$A$3:$B$1000)".format(sheet_name2)
wb.save(org)
wb.close()
で、Excelを確認すると
=@UNIQUE(fugafuga!$A$3:$B$1000)
と記載されており、「#NAME?」というエラーが出る。
@を削除すると期待通りの結果は得られる。
のでアットマークをなんとかしたいぜという人のためのメモ。
解決例
結論から言うとUNIQUE関数はそのままでは使えないっぽいです。
日本語ドキュメントがなかったので機械翻訳に頼ったまとめが下記。
- openpyxlではSORTやUNIQUEのようなExcel関数は初期仕様に含まれていない
- ArrayFormulaを使うことでExcelの配列数式に対応可能
- _xlfnを使うことで初期仕様に含まれていない数式を動かせる
……ということで修正したものがこちら。
from openpyxl import load_workbook
from openpyxl.worksheet.formula import ArrayFormula
from openpyxl.utils import FORMULAE
org = 'hogeExcel.xlsx'
sheet_name = 'fuga'
sheet_name2 = 'fugafuga'
wb = load_workbook(org)
ws = wb[sheet_name]
# 変更箇所
alist = list(wb[sheet_name2]['A3:D1000'])
blist = [list(tup) for tup in zip(*alist)] # 要素取り出し
clist = [list(x) for x in zip(*blist)] # 転置
cnts = len(set(list(map(lambda c: str(c[0].value)+str(c[1].value), clist)))) # UNIQUE後の長さ
if "UNIQUE" in FORMULAE:
ws["C2"] = ArrayFormula("C2:D{0}".format(cnts+2), "=UNIQUE({0}!$A$3:$B$1000)".format(sheet_name2))
else:
ws["C2"] = ArrayFormula("C2:D{0}".format(cnts+2), "=_xlfn.UNIQUE({0}!$A$3:$B$1000)".format(sheet_name2))
wb.save(org)
wb.close()
"UNIQUE" in FORMULAE
でopenpyxlの初期仕様に含まれている数式か判定していますが、SORTやUNIQUEは含まれていないのが分かっているのでこれはおまじないです。
ほかの関数使うときに使いたいやつ。
ArrayFormulaの引数は単純に(戻り値範囲,数式)でよいかと。
ここの引数をずっと間違えていてファイル開けなかったので戻り値範囲を正しく入力しましょう……。
あと、戻り値範囲をしているように、たとえ配列だろうが1行しか返さない仕組みのようなので、UNIQUEみたいに列数が可変のものは範囲も可変にしておいた方が安牌かなと。
1行ずつ貼られると思ってなかったので、そのまま広めの範囲したら#N/A地獄が始まりました。つらい。
ちなみにArrayFormulaはopenpyxl v3.0にはなかったです。
v3.1.4に上げたら動いたので、バージョン古そうな人はそのあたりにアプデするとよいかも。