Permalink
Browse files

implemented edit-distance based relevant sort

Signed-off-by: Rifat Nabi <to.rifat@gmail.com>
  • Loading branch information...
1 parent 2f04ab5 commit 1d90d169d99722fa26c07845411b6dc2f800564e @torifat torifat committed Jul 1, 2012
Showing with 133 additions and 19 deletions.
  1. +31 −9 AvroKeyboard.xcodeproj/project.pbxproj
  2. +16 −0 NSString+Levenshtein.h
  3. +62 −0 NSString+Levenshtein.m
  4. +1 −1 Suggestion.h
  5. +23 −9 Suggestion.m
@@ -26,6 +26,7 @@
359C1C70159286750080E2FD /* Candidates.m in Sources */ = {isa = PBXBuildFile; fileRef = 359C1C6F159286750080E2FD /* Candidates.m */; };
35B007CB1597BF9A000CE409 /* PreferencesController.m in Sources */ = {isa = PBXBuildFile; fileRef = 35B007CA1597BF9A000CE409 /* PreferencesController.m */; };
35B47478159A668D00C69C7D /* avro.icns in Resources */ = {isa = PBXBuildFile; fileRef = 35B47477159A668D00C69C7D /* avro.icns */; };
+ 35B6EE6D15A0C4F2004C7C9B /* NSString+Levenshtein.m in Sources */ = {isa = PBXBuildFile; fileRef = 35B6EE6C15A0C4F2004C7C9B /* NSString+Levenshtein.m */; };
35DBC86B1597A15B00B9772E /* MainMenuAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 35DBC86A1597A15B00B9772E /* MainMenuAppDelegate.m */; };
35F4DE73159404A3001EAC81 /* data.json in Resources */ = {isa = PBXBuildFile; fileRef = 35F4DE72159404A3001EAC81 /* data.json */; };
35F4DE7F1594096B001EAC81 /* AvroParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 35F4DE7E1594096B001EAC81 /* AvroParser.m */; };
@@ -73,6 +74,8 @@
35B007C91597BF9A000CE409 /* PreferencesController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreferencesController.h; sourceTree = "<group>"; };
35B007CA1597BF9A000CE409 /* PreferencesController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PreferencesController.m; sourceTree = "<group>"; };
35B47477159A668D00C69C7D /* avro.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = avro.icns; sourceTree = "<group>"; };
+ 35B6EE6B15A0C4F2004C7C9B /* NSString+Levenshtein.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+Levenshtein.h"; sourceTree = "<group>"; };
+ 35B6EE6C15A0C4F2004C7C9B /* NSString+Levenshtein.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+Levenshtein.m"; sourceTree = "<group>"; };
35DBC8691597A15B00B9772E /* MainMenuAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainMenuAppDelegate.h; sourceTree = "<group>"; };
35DBC86A1597A15B00B9772E /* MainMenuAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainMenuAppDelegate.m; sourceTree = "<group>"; };
35F4DE72159404A3001EAC81 /* data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = data.json; sourceTree = "<group>"; };
@@ -104,9 +107,8 @@
isa = PBXGroup;
children = (
35B007C51597BF56000CE409 /* Controllers */,
- 350CECED159C45870009F0FE /* FMDatabase */,
- 350CECEE159C45C50009F0FE /* RegexKit */,
35B007CC1597BFC3000CE409 /* Others */,
+ 35B6EE6915A0C4AD004C7C9B /* Libraries */,
35DBC8691597A15B00B9772E /* MainMenuAppDelegate.h */,
35DBC86A1597A15B00B9772E /* MainMenuAppDelegate.m */,
);
@@ -223,6 +225,20 @@
35B007CC1597BFC3000CE409 /* Others */ = {
isa = PBXGroup;
children = (
+ 35B6EE6815A0C4A4004C7C9B /* Parsers */,
+ 350CED19159CF3300009F0FE /* Suggestion.h */,
+ 350CED1A159CF3300009F0FE /* Suggestion.m */,
+ 3553A33315A0009D00FE8491 /* CacheManager.h */,
+ 3553A33415A0009E00FE8491 /* CacheManager.m */,
+ 359C1C6E159286750080E2FD /* Candidates.h */,
+ 359C1C6F159286750080E2FD /* Candidates.m */,
+ );
+ name = Others;
+ sourceTree = "<group>";
+ };
+ 35B6EE6815A0C4A4004C7C9B /* Parsers */ = {
+ isa = PBXGroup;
+ children = (
35895BEE1597639A00F2A3ED /* AutoCorrect.h */,
35895BEF1597639A00F2A3ED /* AutoCorrect.m */,
35F4DE7D1594096B001EAC81 /* AvroParser.h */,
@@ -231,14 +247,19 @@
350CECE4159C45790009F0FE /* RegexParser.m */,
350CED17159CF3300009F0FE /* Database.h */,
350CED18159CF3300009F0FE /* Database.m */,
- 350CED19159CF3300009F0FE /* Suggestion.h */,
- 350CED1A159CF3300009F0FE /* Suggestion.m */,
- 3553A33315A0009D00FE8491 /* CacheManager.h */,
- 3553A33415A0009E00FE8491 /* CacheManager.m */,
- 359C1C6E159286750080E2FD /* Candidates.h */,
- 359C1C6F159286750080E2FD /* Candidates.m */,
);
- name = Others;
+ name = Parsers;
+ sourceTree = "<group>";
+ };
+ 35B6EE6915A0C4AD004C7C9B /* Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ 350CECED159C45870009F0FE /* FMDatabase */,
+ 350CECEE159C45C50009F0FE /* RegexKit */,
+ 35B6EE6B15A0C4F2004C7C9B /* NSString+Levenshtein.h */,
+ 35B6EE6C15A0C4F2004C7C9B /* NSString+Levenshtein.m */,
+ );
+ name = Libraries;
sourceTree = "<group>";
};
/* End PBXGroup section */
@@ -325,6 +346,7 @@
350CED1B159CF3300009F0FE /* Database.m in Sources */,
350CED1C159CF3300009F0FE /* Suggestion.m in Sources */,
3553A33515A0009E00FE8491 /* CacheManager.m in Sources */,
+ 35B6EE6D15A0C4F2004C7C9B /* NSString+Levenshtein.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
@@ -0,0 +1,16 @@
+//
+// NSString+Levenshtein.h
+// Levenshtein
+//
+// Created by Stefano Pigozzi on 8/20/09.
+// Copyright 2009 Stefano Pigozzi. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface NSString (Levenshtein)
+
+-(int) computeLevenshteinDistanceWithString:(NSString *) string;
+
+@end
View
@@ -0,0 +1,62 @@
+//
+// NSString+Levenshtein.m
+// Levenshtein
+//
+// Created by Stefano Pigozzi on 8/20/09.
+// Copyright 2009 Stefano Pigozzi. All rights reserved.
+//
+
+#import "NSString+Levenshtein.h"
+#include <stdlib.h>
+
+@implementation NSString (Levenshtein)
+
+/// minimum between three values
+int minimum(int a,int b,int c)
+{
+ int min=a;
+ if(b<min)
+ min=b;
+ if(c<min)
+ min=c;
+ return min;
+}
+
+
+-(int) computeLevenshteinDistanceWithString:(NSString *) string
+{
+ int *d; // distance vector
+ int i,j,k; // indexes
+ int cost, distance;
+
+ int n = [self length];
+ int m = [string length];
+
+ if( n!=0 && m!=0 ){
+
+ d = malloc( sizeof(int) * (++n) * (++m) );
+
+ for( k=0 ; k<n ; k++ )
+ d[k] = k;
+ for( k=0 ; k<m ; k++ )
+ d[k*n] = k;
+
+ for( i=1; i<n ; i++ ) {
+ for( j=1 ;j<m ; j++ ) {
+ if( [self characterAtIndex:i-1] == [string characterAtIndex:j-1])
+ cost = 0;
+ else
+ cost = 1;
+ d[j*n+i]=minimum(d[(j-1)*n+i]+1,d[j*n+i-1]+1,d[(j-1)*n+i-1]+cost);
+ }
+ }
+ distance = d[n*m-1];
+ free(d);
+ return distance;
+ }
+
+ return -1; // error
+}
+
+
+@end
View
@@ -8,7 +8,7 @@
#import <Foundation/Foundation.h>
@interface Suggestion : NSObject {
- NSMutableArray* suggestions;
+ NSMutableArray* _suggestions;
}
+ (void)allocateSharedInstance;
View
@@ -10,6 +10,7 @@
#import "AutoCorrect.h"
#import "RegexParser.h"
#import "Database.h"
+#import "NSString+Levenshtein.h"
@implementation Suggestion
@@ -21,7 +22,7 @@ - (id)init {
[AvroParser allocateSharedInstance];
[AutoCorrect allocateSharedInstance];
[Database allocateSharedInstance];
- suggestions = [[NSMutableArray alloc] initWithCapacity:0];
+ _suggestions = [[NSMutableArray alloc] initWithCapacity:0];
}
return self;
@@ -52,25 +53,38 @@ - (NSMutableArray*)getList:(NSString*)term {
// Suggestion form AutoCorrect
NSString* autoCorrect = [[AutoCorrect sharedInstance] find:term];
if (autoCorrect) {
- [suggestions addObject:autoCorrect];
+ [_suggestions addObject:autoCorrect];
}
// Suggestion from Dictionary
NSArray* dicList = [[Database sharedInstance] find:term];
+ // Suggestion from Default Parser
+ NSString* paresedString = [[AvroParser sharedInstance] parse:term];
if (dicList) {
- [suggestions addObjectsFromArray:dicList];
+ // Sort dicList based on edit distance
+ NSArray* sortedDicList = [dicList sortedArrayUsingComparator:^NSComparisonResult(id left, id right) {
+ int dist1 = [paresedString computeLevenshteinDistanceWithString:(NSString*)left];
+ int dist2 = [paresedString computeLevenshteinDistanceWithString:(NSString*)right];
+ if (dist1 < dist2) {
+ return NSOrderedAscending;
+ }
+ else if (dist1 > dist2) {
+ return NSOrderedDescending;
+ } else {
+ return NSOrderedSame;
+ }
+ }];
+ [_suggestions addObjectsFromArray:sortedDicList];
if (autoCorrect && [dicList containsObject:autoCorrect]) {
- [suggestions removeObjectIdenticalTo:autoCorrect];
+ [_suggestions removeObjectIdenticalTo:autoCorrect];
}
}
- // Suggestion from Default Parser
- NSString* paresedString = [[AvroParser sharedInstance] parse:term];
- if ([suggestions containsObject:paresedString] == NO) {
- [suggestions addObject:paresedString];
+ if ([_suggestions containsObject:paresedString] == NO) {
+ [_suggestions addObject:paresedString];
}
- return suggestions;
+ return _suggestions;
}
@end

0 comments on commit 1d90d16

Please sign in to comment.