2ã€ã®ã³ã¬ã¯ã·ã§ã³ãæ¥ç¶ãããã
LINQ to Objectsã䜿çšããŠã³ã¬ã¯ã·ã§ã³ãã°ã«ãŒãåãããããããšããããããŸãã ããã«ãããã°ã«ãŒãåãŸãã¯ãã€ã³ãçšã«éžæãããããŒãæ¯èŒãããŸãã
幞ããªããšã«ããããã®æäœã®ã³ã¹ãã¯OïŒnïŒã§ãã ããããå€§èŠæš¡ãªã³ã¬ã¯ã·ã§ã³ã®å Žåãæ¯èŒèªäœã®æå¹æ§ã¯ç§ãã¡ã«ãšã£ãŠéèŠã§ãã æååãããŒãšããŠéžæãããŠããå Žåãã©ã®æ¯èŒå®è£
ãããã©ã«ãã§äœ¿çšãããŸããããã®å®è£
ã¯æååã«é©ããŠããŸããïŒ
clients.Join(orders, c => c.Name, o => o.ClientName, (c, o) => CreateOrederDto(c, o));
ãŠãŒã¶ãŒãæç€ºçã«æå®ããªãå Žåãã³ã³ãã¬ãŒã¿ãŒã®å®è£
ã¯ã©ã®ããã«éžæãããŸããïŒ
Joinã¡ãœããã®ãœãŒã¹ã³ãŒãã§æ¬¡ã®åäœã確èªã§ããŸãã
public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector) { if (outer == null) throw Error.ArgumentNull("outer"); if (inner == null) throw Error.ArgumentNull("inner"); if (outerKeySelector == null) throw Error.ArgumentNull("outerKeySelector"); if (innerKeySelector == null) throw Error.ArgumentNull("innerKeySelector"); if (resultSelector == null) throw Error.ArgumentNull("resultSelector"); return JoinIterator<TOuter, TInner, TKey, TResult>(outer, inner, outerKeySelector, innerKeySelector, resultSelector, null); } static IEnumerable<TResult> JoinIterator<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector, IEqualityComparer<TKey> comparer) { Lookup<TKey, TInner> lookup = Lookup<TKey, TInner>.CreateForJoin(inner, innerKeySelector, comparer); foreach (TOuter item in outer) { Lookup<TKey, TInner>.Grouping g = lookup.GetGrouping(outerKeySelector(item), false); if (g != null) { for (int i = 0; i < g.count; i++) { yield return resultSelector(item, g.elements[i]); } } } }
ãŸããnullã¯JoinIteratorã¡ãœããã«æž¡ãããå
éšã§ãã§ãã¯ã¯è¡ãããŸããããŸããCreateForJoinã¡ãœããã«Lookupãäœæãããšãã«ããã©ã¡ãŒã¿ãŒãšããŠnullãæž¡ãããŸãã
ãŸãã«Lookupã䜿çšããããšã¯ãæç€ºçã«èŠã€ããããšãã§ããŸãã ãã®ã¯ã©ã¹ã¯ãããŒã«ããèŠçŽ ãžã®ã¢ã¯ã»ã¹ãåããã³ã¬ã¯ã·ã§ã³ã§ãããããŒããšã«ããã€ãã®èŠçŽ ãä¿åã§ããŸããååšããªãããŒã«ããã¢ã¯ã»ã¹è©Šè¡ã®å Žåã 空ã®ã³ã¬ã¯ã·ã§ã³ãåã«è¿ãããŸããCreateForJoinã¡ãœããã«èå³ããããŸãïŒ
internal static Lookup<TKey, TElement> CreateForJoin(IEnumerable<TElement> source, Func<TElement, TKey> keySelector, IEqualityComparer<TKey> comparer) { Lookup<TKey, TElement> lookup = new Lookup<TKey, TElement>(comparer); ... } Lookup(IEqualityComparer<TKey> comparer) { if (comparer == null) comparer = EqualityComparer<TKey>.Default; this.comparer = comparer; groupings = new Grouping[7];
EqualityComparer
ãžã§ããªãã¯ã€ã³ã¿ãŒãã§ã€ã¹
IEqualityComparer <T>ã«ã¯ãæœè±¡ã¯ã©ã¹
EqualityComparer <T>ã®åœ¢åŒã®åºæ¬çãªå®è£
ããããŸãããã®ã¯ã©ã¹ã«ã¯ãç¹å®ã®ã¯ã©ã¹Tã®æ¢å®ã®ã³ã³ãã¬ãŒã¿ãéžæããéçãª
Defaultããããã£ããããŸããã€ãŸããTãã¯ã©ã¹ãæ§é ããŸãã¯åçŽåãã®ã¿ã€ãã®ãªããžã§ã¯ãã®çŸåšã®ã³ã³ãã¬ãŒã¿ãŒãéžæãããŸãã
å®å
šãªéžæã³ãŒã ïŒã¿ã€ãã«ãã£ãŠç°ãªã
ãŸã ïŒã¯ããªãè¯ããã§ãããJoinãšGroupByã®äœæ¥ãçè§£ãããšãã芳ç¹ããã¯è峿·±ããã®ã§ãã
- ãã€ãã®å Žåãç¹å¥ãªByteEqualityComparerãéžæãããŸãã ãã®ã¯ã©ã¹ã¯ããã€ãé
åã®IndexOfå®è£
ãå«ãããããã€ãé
åãæ¯èŒãããšãã®ããã©ãŒãã³ã¹ãæ¹åããããã«èšèšãããŠããŸãã
- TãIEquatable <T>ã€ã³ã¿ãŒãã§ã€ã¹ãå®è£
ããå ŽåãIEquatable <T> .EqualsïŒTïŒã¡ãœããã®å®è£
ã®åŒã³åºãã«åºã¥ããŠãªããžã§ã¯ããæ¯èŒããGenericEqualityComparer <T>ãéžæãããŸãã ããã«ãåŒã³åºãåã«ãäž¡æ¹ã®ãã©ã¡ãŒã¿ãŒãnullã®äžçåŒããã§ãã¯ããŸãã
- TãIEquatable <U>ãå®è£
ããNullable <U>ã§ããå Žåã以åã®ãã®ãšåæ§ã§ã远å ã®HasValueãã§ãã¯ãå«ãNullableEqualityComparer <T>ã¯ã©ã¹ã䜿çšãããŸãã
- åæåã®å Žåãåºæ¬åã«å¿ããŠãEnumEqualityComparer <T>å®è£
ã®1ã€ãéžæãããŸãïŒlongåã®å Žåãç¬èªã®ç¹å¥ãªå®è£
ããããŸãïŒãããã¯ãåæå€ãæ°å€ã«å€æããæ¹æ³ã®JITæé©åã®ã¿ãç°ãªããŸãã
- ãã以å€ã®å Žåã¯ãã¹ãŠãObject.Equalsã«åºã¥ããŠãªããžã§ã¯ããæ¯èŒããObjectEqualityComparer <T>ã䜿çšãããŸã ã ããã§ã¯ããã¹ãŠãéåžžã©ããã§ã-åç
§åã®å Žåããªã³ã¯ã®ç䟡æ§ãéèŠãªåã®å Žå-ãªããžã§ã¯ãã®åã®äžèŽïŒObjectEqualityComparer <T>ã®å Žåã¯åžžã«trueïŒããã³ãªããžã§ã¯ãã®ãã¹ãŠã®ãã£ãŒã«ãã®å€ã®äžèŽã
Stringã¯ã©ã¹ã¯IEquatable <T>ã€ã³ã¿ãŒãã§ã€ã¹ãå®è£
ãããããæååãæ¯èŒãããšãã«ãã®ã€ã³ã¿ãŒãã§ã€ã¹ã®å®è£
ãåŒã³åºãããŸãã
.NET Coreã®å Žåãã³ã³ãã¬ãŒã¿ãŒãéžæããããã©ã«ãã®å®è£
ã¯ç°ãªããŸã -æååã®å Žåã EqualityComparerForStringãéžæãããæ¯èŒã«ç䟡==æŒç®åã®ã¿ã䜿çšãããŸããæå忝èŒ
String.EqualsïŒæååå€ïŒã¡ãœããã¯ãæåååç
§ã®ç䟡æ§ãæååã®é·ãã®ç䟡æ§ããã§ãã¯ãããããã®ããããã£ã«åºã¥ããŠç䟡æ§ãèšç®ã§ããªã
å Žåãæååãããã¡ã® ïŒã»ãŒïŒ
ãã€ãæ¯èŒãåŒã³åºã
ãŸã ã
[System.Security.SecuritySafeCritical]
çç£æ§ãé«ããããã«ãMicrosoft
ã¯ã«ãŒããè§£ãã»ãããŸãã ã
ãã®ãã
ãããã©ã«ãã§ã¯ããããã®è¡ã®å
容ã®ãã€ãæ¯èŒã䜿çšãããŸãã 广çã«ïŒ ããããã ãããŠãä»ã«ã©ã®ããã«æååãæ¯èŒã§ããŸããïŒ
StringComparer
Stringã¯ã©ã¹ã®å Žåã.netã«ã¯
StringComparerã³ã³ãã¬ãŒã¿ã®ç¬èªã®æœè±¡å®è£
ãšãããããç¶æ¿ãããããã€ãã®ã¯ã©ã¹ãããããã®ã¯ã©ã¹ã®éçããããã£ãä»ããŠã€ã³ã¹ã¿ã³ã¹ã«ã¢ã¯ã»ã¹ã§ããŸãã 3ã€ã®ã¿ã€ãã®æå忝èŒã«ã¯ããããã倧æåãšå°æåã®åºå¥ã®æç¡ã«ããããã6ã€ã®å®è£
ããããŸãã
- CurrentCulture / CurrentCultureIgnoreCase-çŸåšã®æåãšèšèªïŒçŸåšã®ã¹ã¬ããã®æåïŒã®ã«ãŒã«ãèæ
®ãããåèªã«ããæ¯èŒ
- InvariantCulture / InvariantCultureIgnoreCase-èšèªãšæåããã³èšèªã®èŠåãèæ
®ããã«åèªã«åŸã£ãŠæ¯èŒããïŒCultureInfo.InvariantCultureã䜿çšïŒ
- Ordinal / OrdinalIgnoreCase-ãã€ãæ¯èŒ
StringComparerã¯IEqualityComparer <string>ãå®è£
ããããããã®åå«ã¯ãã¹ãŠIEqualityComparer <string>ãæåŸ
ããããã©ã¡ãŒã¿ãŒãšããŠæå®ã§ããŸãããããã®æ¯èŒæ¹æ³ã®èª¬æã«äœåºŠãåºäŒã£ãããšããããŸããããçŸåšã®æåãèæ
®ããèšèã«ããæ¯èŒããäœãæå³ããã®ããç§ã¯æ¬åœã«çåã«æããŸããã§ããã
ãã€ãæ¯èŒã¯ãEqualityComparer <String> .DefaultãéžæãããŠããå ŽåããŸãã¯Equalsã¡ãœãããæç€ºçã«åŒã³åºãããå Žåãšåãã§ããïŒ ãã®å Žåã
OrdinalComparerã¯ã©ã¹ã
æ¯èŒãæ
åœããŸãã
public override bool Equals(string x, string y) { if (Object.ReferenceEquals(x ,y)) return true; if (x == null || y == null) return false; if( _ignoreCase) { if( x.Length != y.Length) { return false; } return (String.Compare(x, y, StringComparison.OrdinalIgnoreCase) == 0); } return x.Equals(y); }
倧æåãšå°æåãåºå¥ããå Žåãéãã¯ãªããžã§ã¯ãåç
§ã®ç䟡æ§ã®éè€ãã§ãã¯ãšnullã®ãã§ãã¯ã«ãããŸãã ããã¯ããã»ã©å€ããããŸããããMSILã®èгç¹ããã¯ãæ°åã®åœä»€ã§ãã
IL_0000: nop IL_0001: ldarg.0 IL_0002: ldarg.1 IL_0003: call bool [mscorlib]System.Object::ReferenceEquals(object, object) IL_0008: ldc.i4.0 IL_0009: ceq IL_000b: stloc.1 IL_000c: ldloc.1 IL_000d: brtrue.s IL_0013 IL_000f: ldc.i4.1 IL_0010: stloc.0 IL_0011: br.s IL_003e IL_0013: ldarg.0 IL_0014: brfalse.s IL_001f IL_0016: ldarg.1 IL_0017: ldnull IL_0018: ceq IL_001a: ldc.i4.0 IL_001b: ceq IL_001d: br.s IL_0020 IL_001f: ldc.i4.0 IL_0020: nop IL_0021: stloc.1 IL_0022: ldloc.1 IL_0023: brtrue.s IL_0029 IL_0025: ldc.i4.0 IL_0026: stloc.0 IL_0027: br.s IL_003e
倧æåãšå°æåãåºå¥ããªãä¿åã¯ã©ãã§ããïŒ ççŽã«èšã£ãŠããã®æäœã¯æåã«äŸåããããã
ToLowerã®ãããªãã®ã¯æåŸ
ããŠããŸããã§ããã ããããçµæã¯ãŸã æåŸ
ãè¶
ããŠããŸããã String.CompareïŒxãyãStringComparison.OrdinalIgnoreCaseïŒãåŒã³åºãã«ã¯ã次ã®
ã³ãŒããã©ã³ããå®è¡ãããŸãã
case StringComparison.OrdinalIgnoreCase: if (this.Length != value.Length) return false;
IsAsciiãã¹ããæ£åœåããããã«ãã©ãã»ã©æªã倿ãäžãå¿
èŠãããã®ã§ããããã
ASCIIæååã®å Žåãæ€èšŒã¯å®éã«æåããšã«å®è¡ãããåæåã®å€§æåãšå°æåããã§ãã¯ãããå¿
èŠã«å¿ããŠ0x20ã®åçŽãªæžç®ã«ãã£ãŠå€§æåã«å€æãããŸãã
private unsafe static int CompareOrdinalIgnoreCaseHelper(String strA, String strB) { int length = Math.Min(strA.Length, strB.Length); fixed (char* ap = &strA.m_firstChar) fixed (char* bp = &strB.m_firstChar) { char* a = ap; char* b = bp; while (length != 0) { int charA = *a; int charB = *b; Contract.Assert((charA | charB) <= 0x7F, "strings have to be ASCII");
éASCIIæååã®å Žåã
ãã€ãã£ã C ++
ã³ãŒããåŒã³åºãããæ¡ä»¶ã«å¿ããŠãWindowsã«ãŒãã«ããã®æååãæ¯èŒããããã®ã¡ãœãããåŒã³åºãããšãã§ããŸãïŒã³ã¡ã³ãã«ãã£ãŠå€æãããšãããã¯Windows XPã§ã®ã¿å¯èœã§ãïŒåãæåããšã®æ¯èŒãå®è¡ããåæåãäžäœã«å€æãã
ã¡ãœãããªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã®æåããŒãã«ã®ã±ãŒã¹ããŒã¹ã®ã¬ãžã¹ã¿ã
åãã³ã³ãã¬ãŒã¿ã®ããã©ãŒãã³ã¹ã¯ãçž®éã®å Žåãè¡ã®1æåã倿Žããããšã«ãããå
¥åããŒã¿ã«å¿ããŠç°ãªãå Žåããããããããã¯å®éã«ããã©ãŒãã³ã¹ã®åé¡ã«é¢å¿ãåŒãèµ·ãããŸããäœç©ã¯ã©ãã§ããïŒ
CultureAwareComparerã¯ã©ã¹ã¯ã«ã«ãã£ãå
¥åãšããŠåãå
¥ããããã«åºã¥ããŠæååãšã±ãŒã¹ãç¡èŠããããã©ããã瀺ããã©ã°ãæ¯èŒããŸãã ã«ã«ãã£ã«é¢ããæ
å ±ã«ã¯
CompareInfoããããã£ãå«ãŸãããã®ãªããžã§ã¯ãã«ã¯CultureAwareComparerã§äœ¿çšããããã®ã«ã«ãã£ãèæ
®ããŠæååãæ¯èŒããã¡ãœãããå«ãŸããŸãã
return (_compareInfo.Compare(x, y, _ignoreCase? CompareOptions.IgnoreCase : CompareOptions.None) == 0);
æ®å¿µãªãããå®éã«ã¯
ãã€ãã£ãã³ãŒããåŒã³åºãããåã³ã«ãŒãã«ã«ã¯ããŒã«ãããŠæååãœãŒã颿°ãåŒã³åºããããããå
éšã«ã¯è峿·±ããã®ã¯ãããŸããã ã³ãŒãã®äžè¶³ãè£ãããã«ãcoreclrã®æåå颿°ã§ç¹°ãè¿ãèŠãããæç²ã次ã«ç€ºããŸãã
ã€ãŸãã
æåãšèšèªã«é¢ãã.netæååã®æ¯èŒã¯ã
åžžã«ãªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã®ã«ãŒãã«ã¬ãã«ã§è¡ãããŸã ã
æ§èœè©Šéš
ãã®ãããªæ
ã®åŸãç§ã¯ããã©ãŒãã³ã¹ã®æ¬åœã®éãã«èå³ãæã€ããã«ãªããŸããã åœåãç§ã®ã·ããªãªã¯ã倿°ã®æ¯èŒã®çµæãšããŠãã·ãŒã±ã³ã¹ãçµåããããšã§ããã ã¯ãªãŒã³ãã¹ãã®ããã«ã远å ã®æäœãè¡ããã«æå忝èŒã®ã¿ãæ®ããŸããã
GitHubã§ãã¹ãã®ãœãŒã¹ã³ãŒãã衚瀺ãŸãã¯ååŸã§ããŸãã çµæã¯å°ãæµ®ããŠããŸãããã1,000,000åã®10,000åã®å埩ã§ãä¿¡é Œåºéããªããã°ååã§ãããšå€æããŸããã
ã¹ã¯ãªãã | ããªç§/ 1,000,000æäœ | çžå¯Ÿå·® |
---|
string.Equals | 25.8 | 1å |
EqualityComparer <string> .Default | 33.5 | 1.3å |
StringComparer.Ordinal | 29.8 | 1.16x |
StringComparer.OrdinalIgnoreCase | 50.3 | 1.95x |
StringComparer.OrdinalIgnoreCase ASCIIä»¥å€ | 82.2 | 3.19x |
StringComparer.CurrentCulture | 136 | 5.27x |
StringComparer.CurrentCultureéASCII | 174.3 | 6.76x |
StringComparer.CurrentCultureIgnoreCase | 134.5 | 5.21x |
StringComparer.CurrentCultureIgnoreCaseéASCII | 172.1 | 6.67x |
StringComparer.InvariantCulture | 132.2 | 5.12x |
StringComparer.InvariantCultureéASCII | 189.5 | 7.34x |
StringComparer.InvariantCultureIgnoreCase | 134.1 | 5.2å |
StringComparer.InvariantCultureIgnoreCaseéASCII | 188 | 7.29x |
çµæã¯ã³ãŒãã確èªããŸã-string.Equalsãžã®æç€ºçãªåŒã³åºãã¯æéã§ãGenericEqualityComparer <string>ã¯å
¥åãã©ã¡ãŒã¿ãŒã®è¿œå ãã§ãã¯ã®ããã«äœéã§ãã OrdinalComparerã«ã¯è¿œå ã®ãã§ãã¯ããããŸãã ãããŠãã¢ã³ã¯ã€ã³ããµã€ã¯ã«ãŸãã¯ã¢ã³ãããŒãžã³ãŒãã¡ãœããã®ãããããåŒã³åºãããŸããããã¯ãäžè¬çã«ãç°ãªããã©ãããã©ãŒã ã§ç°ãªãåäœãããŸãããã«ã«ãã£ãæäœããå Žåããªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã®ã«ãŒãã«ããã¡ãœãããåŒã³åºããŸãã
ä»ã®æååæäœã®æ¯èŒ
ããã©ã«ãã§ã¯ãæéãã€æãç°¡åãªæ¯èŒã䜿çšãããããã«æãããŸãããããã°ã©ãã¯å¿é
ããå¿
èŠã¯ãããŸããã å®éãããã¯å®å
šã«çå®ã§ã¯ãããŸããã æååæäœã¯å€æ°ãããŸãã ããšãã°
ãæååãç¹å®ã®éšåæååã§å§ãŸãã
ã©ããã倿
ããã«ã¯ ïŒ
public Boolean StartsWith(String value) { return StartsWith(value, StringComparison.CurrentCulture); }
åæã«ã
éšåæåå ïŒåãããã«èŠããïŒ
ã®çºçã®ç¢ºèªãããã€ãããšã«å®è¡ãããŸãã
public bool Contains( string value ) { return ( IndexOf(value, StringComparison.Ordinal) >=0 ); }
ãã®éšåæååã®å
é ã®ã€ã³ããã¯ã¹ãè¿ãéšåæååã®åºçŸã®ãã§ãã¯ã¯ãçŸåšã®ã«ã«ãã£ã§ãè¡ãããŸãã
public int IndexOf(String value) { return IndexOf(value, StringComparison.CurrentCulture); }
éåžžãLastIndexOfã¯ãã€ãã£ãã³ãŒããåŒã³åºããŸãã ããã§äœãèµ·ãã£ãŠããŸããïŒ ãµãã£ã€ã ããç¥ã£ãŠããŸãã
çµè«
ããããã¹ãŠã®æ
å ±ãã©ãããŸããïŒ
- ãŸãã倿°ã®æ¯èŒã«ãããstring.Equalsã¡ãœããã«æ¢ã«ååšãããã§ãã¯ãè€è£œããªãç¬èªã®æååã³ã³ãã¬ãŒã¿ãŒãå®è£
ããããšã«ããããããã®æäœã®ããã©ãŒãã³ã¹ãçŽ10ïŒ
åäžãããããšãã§ããŸãã
- 次ã«ãæååãããŒã§ããå Žåãã»ãšãã©ã®æ¯èŒã§çŽ20ïŒ
ã®ã²ã€ã³ãåŸãããAsciiæåã®ã¿ã䜿çšããããšã決å®ã§ããŸãã
- 第äžã«ãæåãèæ
®ããŠæ¯èŒãé©çšãããå Žåãçè§£ããå¶éããå¿
èŠããããŸãã èè
ã¯ãã®æ¯èŒãæãäžè¬çã§ãããšèãããããå€ãã®å Žåãã³ãŒãã§StringComparer.InvariantCultureãªãã·ã§ã³ãšæ£ç¢ºã«äžèŽããŸããã ãã ããã»ãšãã©ã®å ŽåãStringComparer.OrdinalããŸãã¯ç¹å¥ãªå Žåã«ã¯StringComparer.OrdinalIgnoreCaseã䜿çšããã ãã§ååã§ãã
- Stringã¯ã©ã¹ã®ããŸããŸãªã¡ãœããã䜿çšããŠããœãŒã¹ã§ã®åäœãå確èªããããšããå§ãããŸãã ããããããã¹ãããTestStringããšãAnotherTestStringãã§ãã¹ããããåŸãã³ãŒããå®çšŒåã«å
¥ããšé©ãã§ãããã