Swiftの配列で重複を削除する
純粋な言語のオマージュ
func nub<T:Equatable>(_ array: [T] ) -> [T] { return array.reduce([]) { $0.contains($1) ? $0 : $0 + [$1] } } func nub<T>(_ array: [T], isEquivalent: (T,T) -> Bool ) -> [T] { return array.reduce([]) { ( xs: [T], x: T ) -> [T] in xs.filter( { isEquivalent( $0, x ) } ).count != 0 ? xs : xs + [x] } }
let foo = [1,1,2,2,2,3,3,3,4,4] let bar = nub(foo) // bar == [1, 2, 3, 4] let barbar = nub(foo,isEquivalent:{$0==$1}) // barbar == [1, 2, 3, 4]
順番を変えてしまっていたのでケシケシ。
間違いに気付いて再度ケシケシ。
Set(array).countで足りることに気付いて再びケシケシ。
Swiftで行列の積
前回は幼稚な感動を記事にしたわけですが、今回も引き続きそんなノリです。
protocol VectorProtocol { typealias ComponentType init( _ component : ( index : UInt ) ->ComponentType ) static func dot( lhs: Self , _ rhs: Self ) -> ComponentType } protocol MatrixProtocol { typealias ComponentType typealias RowType typealias ColType func row( index : UInt ) -> RowType func col( index : UInt ) -> ColType init( _ component : ( row : UInt, col : UInt ) -> ComponentType ) } func * < T : MatrixProtocol, U : MatrixProtocol where T.RowType : VectorProtocol, T.RowType == U.ColType, T.ColType == U.RowType, T.ComponentType == T.RowType.ComponentType > ( lhs: T, rhs: U ) -> T { return T() { T.RowType.dot( lhs.row( $0 ), rhs.col( $1 ) ) } }
row majorだろうが、column majorだろうが、2x3と3x4だろうが、各種正方行列だろうが、要素の型がなんであろうが、これからはプロトコル準拠するだけで済むのかぁ。良い時代だなぁ、しかし。ちょーでかい行列は使わないのでわかりません。
protocolにextensionが書けるって素敵
個人的にGLSLやOpenCLなんかのswizzeringが好きで、オレオレのベクタ型にはそれっぽいのを必ず用意してたりします。
SwiftはずーっとTLの狼狽を眺めてばかりでやり過ごしてたのですが、このswizzeringを一番そっくりに使えそうなのに気づいてすこし格闘してました。最悪の場合、type毎に、別の言語でソースコード生成してしまおうかとボンヤリしてたら、ふっと、「もしかして?」みたいな感じで、protocolにextensionを書いてみたところ、ばっちり動いてくれました。
Swift情報に疎く、ほぼSwift初心者なので、ネットに頼らず自力で発見できたことが嬉しくて、記録として残そうと思った次第です。
CGPointだけだと過剰ですな。でも、3要素や4要素あるベクタが複数あるとき、あるいは色々試したいとき、これからは楽できそう。
protocol Component2Swizzering { typealias ItemType typealias Component2Type var x: ItemType { get set } var y: ItemType { get set } func C2_INIT( x x: ItemType, y: ItemType ) -> Component2Type func X_C2( c : Component2Type ) -> ItemType func Y_C2( c : Component2Type ) -> ItemType }
extension Component2Swizzering { var xy : Component2Type { get { return C2_INIT( x: x, y: y ) } set(p) { x = X_C2(p); y = Y_C2(p) } } var yx : Component2Type { get { return C2_INIT( x: y, y: x ) } set(p) { x = Y_C2(p); y = X_C2(p) } } var xx : Component2Type { get { return C2_INIT( x: x, y: x ) } } var yy : Component2Type { get { return C2_INIT( x: y, y: y ) } } }
extension CGPoint : Component2Swizzering{ typealias Component2Type = CGPoint func C2_INIT(x x:ItemType,y:ItemType) -> Component2Type { return CGPoint( x: x, y: y ) } func X_C2(c : Component2Type ) -> ItemType { return c.x } func Y_C2(c : Component2Type ) -> ItemType { return c.y } }
var point : CGPoint = CGPointMake(10, 20) // point変数に(10.0,20.0)が入ってる print( point.yz ) // だけど(20.0,10.0) と表示される
+stringWithFormat:
+stringWithFormat:って、大量に使うとソースコードが読みにくくて仕方ないことしばしば。
そこで最近は以下のようなマクロをよく使っています。
#define FORMAT( ... ) [NSString stringWithFormat:__VA_ARGS__]
[NSString stringWithFormat:@"HOGEHOGE %@ %@",obj0,obj1]
とするかわりに、
FORMAT(@"HOGEHOGE %@ %@",obj0,obj1)
と書いてます。
ろっく
Mac OS XのOpenGL contextがマルチスレッド対応になりまっせと発表があって久しいわけですが、
どうマルチスレッド対応してるのかなんとなく不思議ではありました。
使う側の注意としては、コンテキストをロックするべしっていうのが正解みたいです。
とりあえず僕は以下のようにしてます。NSOpenGLViewをサブクラス化したクラスでつかっているメソッドの一部です。
正確なところはサンプルコードやリファレンスあさってください。
間違いがあるようであればこっそり教えて頂けると嬉しいです。
- (void)openGLDraw { CGLContextObj ctx = [[self openGLContext] CGLContextObj]; CGLLockContext(ctx); [[self openGLContext] makeCurrentContext]; // draw something. CGLFlushDrawable(ctx); CGLUnlockContext(ctx); }
glのapiのエントリーポイント的にそりゃそーかって感じですな。
color wellっぽいcell
NSColorWellみたいなNSCellがほしいなーと探せどもみつからず。
で、つくってみた。
単に色を表示するだけです。
#import <Foundation/Foundation.h> @interface NJColorCell : NSCell { @private } @end
@implementation NJColorCell - (id)init { self = [super init]; if (self) { // Initialization code here. } return self; } - (void)dealloc { [super dealloc]; } - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { NSRect outsideRect = CGRectInset(cellFrame, 1, 1); NSRect insideRect = CGRectInset(cellFrame, 5, 5); [NSBezierPath setDefaultLineWidth:1.0]; [[NSColor darkGrayColor] setStroke]; [[NSBezierPath bezierPathWithRect:outsideRect] stroke]; NSGradient* aGradient = [[[NSGradient alloc] initWithColorsAndLocations: [NSColor colorWithCalibratedWhite:1.0 alpha:1.0], (CGFloat)0.0, [NSColor colorWithCalibratedWhite:0.83 alpha:1.0], (CGFloat)0.2, [NSColor colorWithCalibratedWhite:1.0 alpha:1.0], (CGFloat)1.0, nil] autorelease]; [aGradient drawInRect:outsideRect angle:90.0]; [[NSColor grayColor] setStroke]; [[self objectValue] setFill]; [[NSBezierPath bezierPathWithRect:insideRect] stroke]; [[NSBezierPath bezierPathWithRect:insideRect] fill]; } @end
NSOutlineViewなんかでの、クリック時はdelegateメソッドの- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
で拾い、delegateクラスでNSColorPanel呼び出しもろもろをゴニョゴニョする方針。
だけどこれだとなんか反応が悪い。何使うのがベストなんでしょうかー?
ただのメモ
忘れやすいので。
+(NSSet*)keyPathsForValuesAffecting<Key>;