IronPython で LINQ 型と拡張メソッドを使用することは可能ですか?
もしそうなら、どのように?また、同じことを行うためのより多くのPythonicがありますか?
IronPython で LINQ 型と拡張メソッドを使用することは可能ですか?
もしそうなら、どのように?また、同じことを行うためのより多くのPythonicがありますか?
clr.ImportExtensions
IronPython 2.7は、拡張メソッドを名前空間からターゲット タイプに追加するメソッドを使用して、このギャップを最終的に埋めます。
>& 'C:\Program Files\IronPython 2.7\ipy.exe'
IronPython 2.7 (2.7.0.40) on .NET 4.0.30319.225
Type "help", "copyright", "credits" or "license" for more information.
>>> import clr
>>> clr.AddReference("System.Core")
>>> from System.Collections.Generic import List
>>> dir (List)
['Add', 'AddRange', 'AsReadOnly', 'BinarySearch', 'Capacity', 'Clear', 'Contains', 'ConvertAll', 'CopyTo', 'Count', 'Enu
merator', 'Equals', 'Exists', 'Find', 'FindAll', 'FindIndex', 'FindLast', 'FindLastIndex', 'ForEach', 'GetEnumerator', '
GetHashCode', 'GetRange', 'GetType', 'IndexOf', 'Insert', 'InsertRange', 'IsReadOnly', 'IsSynchronized', 'Item', 'LastIn
dexOf', 'MemberwiseClone', 'ReferenceEquals', 'Remove', 'RemoveAll', 'RemoveAt', 'RemoveRange', 'Reverse', 'Sort', 'Sync
Root', 'ToArray', 'ToString', 'TrimExcess', 'TrueForAll', '__add__', '__class__', '__contains__', '__delattr__', '__doc_
_', '__format__', '__getattribute__', '__getitem__', '__hash__', '__init__', '__iter__', '__len__', '__new__', '__reduce
__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__']
>>> import System
>>> clr.ImportExtensions(System.Linq)
>>> dir (List)
['Add', 'AddRange', 'Aggregate', 'All', 'Any', 'AsEnumerable', 'AsParallel', 'AsQueryable', 'AsReadOnly', 'Average', 'Bi
narySearch', 'Capacity', 'Cast', 'Clear', 'Concat', 'Contains', 'ConvertAll', 'CopyTo', 'Count', 'DefaultIfEmpty', 'Dist
inct', 'ElementAt', 'ElementAtOrDefault', 'Enumerator', 'Equals', 'Except', 'Exists', 'Find', 'FindAll', 'FindIndex', 'F
indLast', 'FindLastIndex', 'First', 'FirstOrDefault', 'ForEach', 'GetEnumerator', 'GetHashCode', 'GetRange', 'GetType',
'GroupBy', 'GroupJoin', 'IndexOf', 'Insert', 'InsertRange', 'Intersect', 'IsReadOnly', 'IsSynchronized', 'Item', 'Join',
'Last', 'LastIndexOf', 'LastOrDefault', 'LongCount', 'Max', 'MemberwiseClone', 'Min', 'OfType', 'OrderBy', 'OrderByDesc
ending', 'ReferenceEquals', 'Remove', 'RemoveAll', 'RemoveAt', 'RemoveRange', 'Reverse', 'Select', 'SelectMany', 'Sequen
ceEqual', 'Single', 'SingleOrDefault', 'Skip', 'SkipWhile', 'Sort', 'Sum', 'SyncRoot', 'Take', 'TakeWhile', 'ToArray', '
ToDictionary', 'ToList', 'ToLookup', 'ToString', 'TrimExcess', 'TrueForAll', 'Union', 'Where', 'Zip', '__add__', '__clas
s__', '__contains__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__getitem__', '__hash__', '__init__',
'__iter__', '__len__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__'
, '__str__', '__subclasshook__']
>>>
これにより、IronRuby 1.1 のusing_clr_extensions
メソッドに沿ったものになります。
LINQ で行うことのいくつかは、リスト内包表記で行うことができます。
[myFunc(i) for i in numbers if i > 3]
map
または、 、reduce
、およびを使用できますfilter
。
map(myFunc, filter(lambda x: x > 3, numbers))
しかし、リスト内包表記は、関数型プログラミング構造を使用するよりもはるかに "Pythonic" です。物事を減らすには、"".join
またはの使用を検討してsum
ください。any
また、 andを使用して iterable 全体の真偽値を確認できますall
。
これらの翻訳を覚えておいてください:
Select -> map
Where -> filter
Aggregate -> reduce
そして、あなたは順調に進んでいるでしょう!
IronPython 2.7.1には、このユースケース用のclr.ImportExtensionsがあります。
import clr
clr.AddReference("System.Core")
import System
clr.ImportExtensions(System.Linq)
# will print 3 and 4 :)
[2, 3, 4].Where(lambda x: x != 2).ToList().ForEach(System.Console.WriteLine)
少し背景:IronPython 2.7は最初にこの機能を導入しましたが、実際に使用できなくなる問題がありました。
IronPython での C# の「連鎖拡張メソッド」構文と同様の構文を実現するために、LINQ 拡張メソッドの周りにC# ラッパー クラスを記述しました。
IEnumerable
アイデアは、単に拡張メソッドを呼び出す一種のデコレータ クラスを配置することです。おそらく、このラッパー クラスは IronPython でも同様に記述できますが、私はまだ Python に堪能ではありません :-)
public class ToLinq<T> : IEnumerable<T>
{
private readonly IEnumerable<T> _wrapped;
public ToLinq(IEnumerable<T> wrapped)
{
_wrapped = wrapped;
}
public ToLinq<T> Where(Func<T, bool> predicate)
{
return new ToLinq<T>(_wrapped.Where(predicate));
}
// ... similar methods for other operators like Select, Count, Any, ...
}
これにより、次のような構文が可能になります。
johns = ToLinq[Customer](customers)\
.Where(lambda c: c.Name.StartsWith("John"))\
.Select(lambda c: c.Name)
免責事項: これは私が学習演習として試したものです。私は実際のプロジェクトでこれを使用していません。