Алгоритмы и коллекции
стандартных библиотек
C++, C#, Java, Objective-C

Об одной жемчужине Microsoft,
портированной на Obj-C...

Антон Буков
@k06a
Основные сущности
стандартной библиотеки
•

Коллекции (структуры данных)

•

Алгоритмы (универсальные и специальные)

•

Перечислители (iterator, enumerator)
Коллекции.
(структуры данных)
C++
(STL)

Постоянного
размера
Не зависят
от значений

Сравнивают
значения
Считают хеши
и сравнивают
значения

C#
(.NET Framework)

[]
std::array

Array

unordered_set
unordered_map

Obj-C

(Collections Framework) (Foundation Framework)

Array

[]
NSArray

ArrayList
LinkedList
ArrayDeque

NSMutableArray
NSPointerArray

SortedSet
SortedDictionary

TreeSet
TreeMap

NSMutableOrderedSet

Set
Dictionary

HashSet/
LinkedHashSet
HashMap/
LinkedHashMap

NSMutableSet
NSCountedSet
NSHashTable
NSMutableDictionary
NSMapTable

vector list stack List LinkedList
queue deque
Stack Queue
set
map

Java
Иерархия коллекций.
Интерфейсы C# и Java
IEnumerable

Collection

Map

• iterator

• clear

• bool Add
• ∩∪⊂⊃

• containsK/V
• remove

• remove

• Count

• clear

• contains

ISet

• put

• add

ICollection

• size

• size

• GetEnumerator

• entrySet

• Add

• keySet

• Clear

• values

• Contains
• Remove

Queue

Set

• add

IList

IDictionary

• Item[i]

• Item[key]

• Insert

• Add(key,value)

• IndexOf

• ContainsKey

• RemoveAt

• Remove(key)

• element
• remove()
• offer
• peek
• poll

List

Deque

• add(i,o)

SortedSet
• subSet
• headSet
• tailSet
• first
• last

• addF/L

• get

• removeF/L

• set

• getF/L

• indexOf

• offerF/L

• remove(i)

• peekF/L

• subList

• pollF/L

• listIterator

SortedMap
• subMap
• headMap
• tailMap
• firstKey
NSArray
Input
iterator

Output
iterator

Forward
iterator

NSSet

NSMutableArray

NSMutableSet

NSPointerArray

NSCountedSet

NSHashTable

Иерархия коллекций.
C++ и Obj-C

NSOrderedSet
Bidirectional
iterator
Random
Access
iterator

NSDictionary
NSMutableDictionary

NSMapTable

NSMutableOrderedSet
NSIndexSet
NSMutableIndexSet
Иерархия коллекций.
Итераторы в C++ (STL)
Категории

O

X b(a); и b = a;

Может быть увеличен на единицу

I

BD

Выражение

Может быть скопирован и создан по образу и подобию

все

FW

Характеристика

++a и a++

Поддерживает сравнение на равенство/неравенство

a == b и a != b

Может быть разыменован как rvalue для получения значения

*a"
a->m
*a = t"

Может быть разыменован как lvalue для использования слева от
знака присваивания
Может быть создан конструктором по-умолчанию

*a++ = t
X a;

Может быть уменьшен на единицу
Поддерживает арифметические операции + и -

a+n и a—n

Поддерживает сравнения (<, >, <= и >=) между итераторами

a < b и a <= b

Поддерживает операции увеличения += и уменьшения -=

a += n и a -= n

Поддерживает разыменование по индексу

RA

X b(a);"
++a == ++b
--a и a--

a[n]

Может быть скопирован и использован для повторного обхода

RA — Random Access iterator ! I" — Input iterator!
BD" — Bidirectional iterator!
O" — Output iterator!

FW — Forward iterator!
Перечислители
(iterator, enumerator)
C++
for	
  (auto	
  it	
  =	
  arr.begin();	
  
	
  	
  	
  	
  	
  it	
  !=	
  arr.end();	
  ++it)	
  
{	
  
	
  	
  	
  	
  std::cout	
  <<	
  *it;	
  
	
  	
  	
  	
  sum	
  +=	
  *it;	
  
}	
  
//	
  -­‐-­‐it,	
  it+n,	
  it-­‐n

Java

C#
var	
  en	
  =	
  arr.GetEnumerator();	
  
while	
  (en.MoveNext())	
  
{	
  
	
  	
  	
  	
  Console.Write(en.Current);	
  
	
  	
  	
  	
  sum	
  +=	
  en.Current;	
  
}	
  
en.Dispose();	
  //	
  using

Objective-C

Iterator	
  it	
  =	
  arr.iterator();	
  
id	
  en	
  =	
  [arr	
  objectEnumerator];	
  
while	
  (it.hasNext())	
  
id	
  object;	
  
{	
  
while	
  (object	
  =	
  [en	
  nextObject])	
  
	
  	
  	
  	
  int	
  value	
  =	
  (Integer)	
  it.next();	
   {	
  
	
  	
  	
  	
  System.out.print(value);	
  
	
  	
  	
  	
  NSLog(@"%@",	
  object);	
  
	
  	
  	
  	
  sum	
  +=	
  value;	
  
	
  	
  	
  	
  sum	
  +=	
  [object	
  intValue];	
  
}
}
Алгоритмы
(1 из 2)
C++
(STL)

Работа с
множествами

C#
(.NET Framework)

merge set_union
Union Intersect
set_intersect
Except
set_difference

Java

Obj-C

(Collections Framework) (Foundation Framework)

disjoint

unionSet minusSet
intersectSet
removeObjectsInArray

sortedArray*
keysSortedBy*

sort stable_sort
partial_sort

OrderBy ThenBy
OrderByDescending
ThenByDescending

sort sorted

find search
binary_search

List.BinarySearch
List.Find***
IList.IndexOf
Where TakeWhile
SkipWhile

binarySearch
indexOfSubList
filter

all_of any_of
Аггреагирующие none_of count
min max

All Any Count
Sum Average
Min Max

valueForKeyPath
frequency
@avg @count
min max allMatch
anyMatch reduce
@max @min
noneMatch
@sum

Сортировки

Поисковые

indexOfObject*
filterUsing filtered*Using
objectsPassingTest

NSPredicate
NSExpression
Алгоритмы
(2 из 2)
C++
(STL)

Прочие

C#
(.NET Framework)

copy
swap
transform
replace
fill
generate
remove
unique
reverse
rotate
shuffle

List.Reverse
Select
Take
Skip
Enumerable.Repeat
Enumerable.Range

Distinct
Reverse
Join
GroupBy
SelectMany

Java

Obj-C

(Collections Framework) (Foundation Framework)

copy
swap
replaceAll
fill
reverse
rotate
shuffle

@distinctUnionOfObjects
@unionOfObjects
@distinctUnionOfArrays
@unionOfArrays
@unionOfSets
Пример
(1 из 6)
•

Дано:
struct Tweet { id, time, text, url, user_id };
struct User { id, name, nick };
array<Tweet> tweets;
map<int,User> userDict;

•

Найти:
Имя пользователя с максимальным числом твитов за
фиксированную дату (1 сент 2013), содержащих ссылку в поле
url и само количество таких твитов.
Пример
(2 из 6)

С++:
"
map<int,int> countByUserId;!
for (auto it = tweets.begin(); it != tweets.end(); ++it)!
if ("2013-09-01" <= it->time && it->time < "2013-09-02")!
if (it->url != 0)!
countByUserId[it->user_id]++;!

"







auto para = max_element(countByUserId.begin(),!
countByUserId.end(),!
[](pair<int,int> a, pair<int,int> b)!
{ return a.second < b.second; });!
 !
cout << "User = " << userDict[para.first].name << endl!
<< "Value = " << para.second << endl; 

Пример
(3 из 6)

Obj-C:
"
NSMutableDictionary * countByUserId = [NSMutableDictionary dictionary];!
for (Tweet * tweet in tweets)!
if ([@"2013-09-01" compareTo:tweet.time] <= 0 && [tweet.time compareTo:@"2013-09-02"] < 0)!
if (tweet.url != 0) {!
int count = [countByUserId[tweet->user_id] intValue];!
countByUserId[tweet->user_id] = @(count + 1);!
}!

"

int maxCount = 0;!
id maxKey = nil;!
[countByUserId enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {!
if ([obj intValue] > maxCount) {!
maxCount = [obj intValue];!
maxKey = key;!
}!
}];!

"

NSLog(@"User = %@nValue = %d",!
[userDict[maxKey] name],!
maxCount);
Пример
(4 из 6)

Java:
"
HashMap<int,int> countByUserId = new HashMap<int,int>();!
for (Tweet tweet : tweets)!
if ("2013-09-01" <= tweet.time && tweet.time < "2013-09-02")!
if (tweet.url != 0) {!
int count = countByUserId.get(tweet.user_id);!
countByUserId.set(tweet->user_id, (count==null?0:count) + 1);!
}!
 !
int maxCount = 0;!
id maxKey = nil;!
for(Entry<int,int> entry : countByUserId.entrySet()) {!
if (entry.getValue() > maxCount) {!
maxCount = entry.getValue();!
maxKey = entry.getKey();!
}!
}!
 !
System.out.format("User = %snValue = %d",!
userDict.get(maxKey),!
maxCount);
Пример
(5 из 6)

C#:
"

var group = tweets.Where(t => "2013-09-01" <= t.time!
&& t.time < "2013-09-02")!
.Where(t => t.url != null)!
.GroupBy(t => t.user_id)!
.Max(gr => gr.Count());!
 !
Console.WriteLine("User = {0}nValue = {1}",!
userDict[group.Key].name,!
group.Count());
Пример
(6 из 6)

Java 8 (java.util.stream):
"
Entry<int,List<int>> !
entry = tweets.stream()!
.filter(t -> "2013-09-01" <= t.time!
&& t.time < "2013-09-02")!
.filter(t -> t.url != null)!
.groupingBy(t -> t.user_id) // Map<int,List<int>>!
.entrySet().stream()!
.max((a,b) -> Int.compare(a.getValue().size(),!
b.getValue().size()));!
 !
System.out.format("User = %snValue = %d",!
userDict.get(entry.getKey()),!
entry.getValue().size());
Пример
(7 из 6, ага)

Obj-C + NSEnumeratorLinq:
"
var para = [[[[tweets.objectEnumerator!
where:^(Tweet *t){return [@"2013-09-01" compareTo:t.time] <= 0!
&& [t.time compareTo:@"2013-09-02"] < 0;}]!
where:^(Tweet *t){return t.url != null;}]!
groupBy:^(Tweet *t){return t.user_id;}]!
max:^(NSKeyValuePair *p){return @([p.value count]);}];!
 !
NSLog(@"User = %@nValue = %@",!
[userDict[para.key] name],!
[para.value count]);
Сравнение архитектур
стандартных библиотек
С++:
•
•

Иерархия итераторов
Алгоритмы универсальные, зависят от категорий итераторов

С#:
•
•

Иерархия интерфейсов
Алгоритмы универсальные, зависят от интерфейсов, выстраиваются в цепь

Java:
•
•
•

Иерархия интерфейсов
Алгоритмы универсальные, зависят от интерфейсов (java.util.Collections)
Алгритмы универсальные, выстраиваются в цепь (java.util.stream)

Obj-C:
•
•

Иерархия отсутствует, если не считать Immutable-Mutable
Алгоритмы специфичные кроме одного :) [NSEnumerator allObjects]
NSEnumeratorLinq
•

Основные методы:

•

Работа с множествами:

•

where, where_i, ofType

•

concat, concatOne

•

select, select_i

•

union, intersect, except

•

distinct

•

zip

•

skip, skipWhile

•

join, groupJoin

•

take, takeWhile

•
•
•

groupBy, selectMany

•

orderBy, orderByDescending

Экспорт:
•
•

Аккумуляция:
•

toArray, toSet
toDictionary, toLookup

Дополнительно:

•

aggregate, elect, elementAt

•

all, any, none

•

readBytes, readLines

•

min, max

•

keyValueEnumerator

•

sum, average

•

stringByJoin-withSeparator

•

firstOrDefault, lastOrDefault

•

enumerateCharacters
Полезные ссылки
•

Collections Programming Guide - https://developer.apple.com/
library/mac/documentation/cocoa/conceptual/Collections/
Collections.html

•

NSSortDescriptor - http://nshipster.com/nssortdescriptor/

•

NSPredicate - http://nshipster.com/nspredicate/

•

NSExpression - http://nshipster.com/nsexpression/

•

NSOrderedSet - http://nshipster.com/nsorderedset/

•

Key-Value Collection Operators — https://developer.apple.com/
library/mac/documentation/Cocoa/Conceptual/KeyValueCoding/
Articles/CollectionOperators.html

•

https://github.com/robrix/RxCollections

•

https://github.com/k06a/NSEnumeratorLinq
One more thing…
•

Оператор if-null
•

Код на C#:
string priceStr = priceHolder.get(featureName);

PriceLabel.Text = priceStr ?? "$0.99";

•

Код на Obj-C:
NSDictionary *prices = [self.storeManager pricesDictionary];

NSString *p1 = prices[@"com.identifier1"] ?: @"$0.99";