[IOS 开发] Linq数组排序

来源:http://www.prospettivedarte.com 作者:计算机教程 人气:145 发布时间:2019-11-30
摘要:[IOS 开发] Linq数组排序 Tempo 2.0 Tempo is an easy, intuitive JavaScript rendering engine that enablesyou to craft data templates in pure HTML. Linq To Objective-C   原文地址:www.Bkjia.com Bringing a Linq-style fluent query API

[IOS 开发] Linq数组排序

Tempo 2.0

Tempo is an easy, intuitive JavaScript rendering engine that enables you to craft data templates in pure HTML.

Linq To Objective-C

 

原文地址:www.Bkjia.com

Bringing a Linq-style fluent query API to Objective-C.

This project contains a collection of NSArray and NSDictionary methods that allow you to execute queries using a fluent syntax, inspired by Linq. In order to use Linq to Objective-C simply copy the NSArray LinqExtensions.h, NSArray LinqExtensions.m, NSDictionary LinqExtensions.h and NSDictionary LinqExtensions.m files into your project and import the header within any file where you wish to use the API.

Alternatively, you can include these files via CocoaPods.

As an example of the types of query this API makes possible, let's say you have an array of Person instances, each with a surname property. The following query will create a sorted, comma-separated list of the unique surnames from the array:

LINQSelector surnameSelector = ^id(id person){
    return [person name];
};

LINQAccumulator csvAccumulator = ^id(id item, id aggregate) {
    return [NSString stringWithFormat:@%@, %@, aggregate, item];
};

NSArray* surnamesList = [[[[people linq_select:surnameSelector]
                                   linq_sort]
                                   linq_distinct]
                                   linq_aggregate:csvAccumulator];

For a detailed discussion of the history of Linq and why I implemented this API, see the related blog post.

Why use Tempo?
  • Clear separation of concerns: no HTML in your JavaScript files, and no JavaScript in your HTML
  • Makes working with AJAX/JSON content a piece of cake
  • Works in Safari, Chrome, FireFox, Opera, and Internet Explorer 6

Licence

The code within project is made available under the standard MIT licence, see the included licence file.

Key Features
  • Itty-bitty footprint, lightning-fast rendering!
  • No dependencies - Use with or without jQuery
  • Supports partial, nested and conditional templates
  • Support for pre-processing, filter and formatting functions and safe attribute setters
  • Variable injection for inline JavaScript expressions
  • Degrades gracefully if JavaScript is not enabled
  • Configurable syntax for greater compatibility

API Overview

NSArray methods:

  • linq_wherelinq_selectlinq_sortlinq_ofTypelinq_selectManylinq_distinctlinq_aggregatelinq_firstOrNillinq_lastOrNillinq_skiplinq_takelinq_anylinq_alllinq_groupBylinq_toDictionarylinq_countlinq_concatlinq_reverse

    NSDictionary methods:

    • linq_wherelinq_selectlinq_toArraylinq_anylinq_alllinq_countlinq_merge

      NSArray methods

      This section provides a few brief examples of each of the API methods. A number of these examples use an array of Person instances:

      interface Person : NSObject
      
      @property (retain, nonatomic) NSString* name;
      @property (retain, nonatomic) NSNumber* age;
      
      @end
      

      ### linq_where

      - (NSArray*) linq_where:(LINQCondition)predicate;
      

      Filters a sequence of values based on a predicate.

      The following example uses the where method to find people who are 25:

      NSArray* peopleWhoAre25 = [input linq_where:^BOOL(id person) {
          return [[person age] isEqualToNumber:@25];
      }];
      

      ### linq_select

      - (NSArray*) linq_select:(LINQSelector)transform;
      

      Projects each element of a sequence into a new form. Each element in the array is transformed by a 'selector' into a new form, which is then used to populate the output array.

      The following example uses a selector that returns the name of each Person instance. The output will be an array of NSString instances.

      NSArray* names = [input linq_select:^id(id person) {
          return [person name];
      }];
      

      ### linq_sort

      - (NSArray*) linq_sort;
      - (NSArray*) linq_sort:(LINQSelector)keySelector;
      - (NSArray*) linq_sortDescending;
      - (NSArray*) linq_sortDescending:(LINQSelector)keySelector;
      

      Sorts the elements of an array, either via their 'natural' sort order, or via a keySelector.

      As an example of natural sort, the following sorts a collection of NSNumber instances:

      NSArray* input = @[@21, @34, @25];
      NSArray* sortedInput = [input linq_sort]; // 21, 25, 34
      

      In order to sort an array of Person instances, you can use the key selector:

      NSArray* sortedByName = [input linq_sort:^id(id person) {
          return [person name];
      }];
      

      The accompanying 'descending' methods simply reverse the sort order:

      NSArray* input = @[@21, @34, @25];
      NSArray* sortedInput = [input linq_sort]; // 21, 25, 34
      NSArray* sortedInput = [input linq_sortDescending]; // 34, 25, 21
      

      ### linq_ofType

      - (NSArray*) linq_ofType:(Class)type;
      

      Filters the elements of an an array based on a specified type.

      In the following example a mixed array of NSString and NSNumber instances is filtered to return just the NSString instances:

      NSArray* mixed = @[@foo, @25, @bar, @33];
      NSArray* strings = [mixed linq_ofType:[NSString class]];
      

      ### linq_selectMany

      - (NSArray*) linq_selectMany:(LINQSelector)transform;
      

      Projects each element of a sequence to an NSArray and flattens the resulting sequences into one sequence.

      This is an interesting one! This is similar to the select method, however the selector must return an NSArray, with the select-many operation flattening the returned arrays into a single sequence.

      Here's a quick example:

      NSArray* data = @[@foo, bar, @fubar];
      
      NSArray* components = [data linq_selectMany:^id(id string) {
          return [string componentsSeparatedByString:@, ];
      }];
      

      A more useful example might use select-many to return all the order-lines for an array of orders.

      ### linq_distinct

      - (NSArray*) linq_distinct;
      - (NSArray*) linq_distinct:(LINQSelector)keySelector;
      

      Returns distinct elements from a sequence. This simply takes an array of items, returning an array of the distinct (i.e. unique) values in source order.

      The no-arg version of this method uses the default method of comparing the given objects. The version that takes a key-selector allows you to specify the value to use for equality for each item.

      Here's an example that returns the distinct values from an array of strings:

      NSArray* names = @[@bill, @bob, @bob, @brian, @bob];
      NSArray* distinctNames = [names linq_distinct];
      // returns bill, bob and brian
      

      Here's a more complex example that uses the key selector to find people instances with distinct ages:

      NSArray* peopleWithUniqueAges = [input linq_distinct:^id(id person) {
          return [person age];
      }];
      

      ### linq_aggregate

      - (id) linq_aggregate:(LINQAccumulator)accumulator;
      

      Applies an accumulator function over a sequence. This method transforms an array into a single value by applying an accumulator function to each successive element.

      Here's an example that creates a comma separated list from an array of strings:

      NSArray* names = @[@bill, @bob, @brian];
      
      id aggregate = [names linq_aggregate:^id(id item, id aggregate) {
          return [NSString stringWithFormat:@%@, %@, aggregate, item];
      }];
      // returns bill, bob, brian
      

      Here's another example that returns the largest value from an array of numbers:

      NSArray* numbers = @[@22, @45, @33];
      
      id biggestNumber = [numbers linq_aggregate:^id(id item, id aggregate) {
          return [item compare:aggregate] == NSOrderedDescending ? item : aggregate;
      }];
      // returns 45 
      

      ### linq_firstOrNil

      - (id) linq_firstOrNil;
      - (id) linq_firstOrNil:(LINQCondition)predicate;
      

      Returns the first element of an array, or nil if the array is empty.

      ### linq_lastOrNil

      - (id) linq_lastOrNil;
      

      Returns the last element of an array, or nil if the array is empty

      ### linq_skip

      - (NSArray*) linq_skip:(NSUInteger)count;
      

      Returns an array that skips the first 'n' elements of the source array, including the rest.

      ### linq_take

      - (NSArray*) linq_take:(NSUInteger)count;
      

      Returns an array that contains the first 'n' elements of the source array.

      ### linq_any

      - (BOOL) linq_any:(LINQCondition)condition;
      

      Tests whether any item in the array passes the given condition.

      As an example, you can check whether any number in an array is equal to 25:

      NSArray* input = @[@25, @44, @36];
      BOOL isAnyEqual = [input linq_any:^BOOL(id item) {
              return [item isEqualToNumber:@25];
          }];
      // returns YES
      

      ### linq_all

      - (BOOL) linq_all:(LINQCondition)condition;
      

      Tests whether all the items in the array pass the given condition.

      As an example, you can check whether all the numbers in an array are equal to 25:

      NSArray* input = @[@25, @44, @36];
      BOOL areAllEqual = [input linq_all:^BOOL(id item) {
              return [item isEqualToNumber:@25];
          }];
      // returns NO
      

      ### linq_groupBy

      - (NSDictionary*) linq_groupBy:(LINQSelector)groupKeySelector;
      

      Groups the items in an array returning a dictionary. The groupKeySelector is applied to each element in the array to determine which group it belongs to.

      The returned dictionary has the group values (as returned by the key selector) as its keys, with an NSArray for each value, containing all the items within that group.

      As an example, if you wanted to group a number of strings by their first letter, you could do the following:

      NSArray* input = @[@James, @Jim, @Bob];
      
      NSDictionary* groupedByFirstLetter = [input linq_groupBy:^id(id name) {
         return [name substringToIndex:1];
      }];
      // the returned dictionary is as follows:
      // {
      //     J = (James, Jim);
      //     B = (Bob);
      // }
      

      ### linq_toDictionary

      - (NSDictionary*) linq_toDictionaryWithKeySelector:(LINQSelector)keySelector;
      - (NSDictionary*) linq_toDictionaryWithKeySelector:(LINQSelector)keySelector valueSelector:(LINQSelector)valueSelector;
      

      Transforms the source array into a dictionary by applying the given keySelector and (optional) valueSelector to each item in the array. If you use the toDictionaryWithKeySelector: method, or the toDictionaryWithKeySelector:valueSelector: method with a nil valueSelector, the value for each dictionary item is simply the item from the source array.

      As an example, the following code takes an array of names, creating a dictionary where the key is the first letter of each name and the value is the name (in lower case).

      NSArray* input = @[@Frank, @Jim, @Bob];
      
      NSDictionary* dictionary = [input linq_toDictionaryWithKeySelector:^id(id item) {
          return [item substringToIndex:1];
      } valueSelector:^id(id item) {
          return [item lowercaseString];
      }];
      
      // result:
      // (
      //    F = frank;
      //    J = jim;
      //    B = bob;
      // )
      

      Whereas in the following there is no value selector, so the strings from the source array are used directly.

      NSArray* input = @[@Frank, @Jim, @Bob];
      
      NSDictionary* dictionary = [input linq_toDictionaryWithKeySelector:^id(id item) {
          return [item substringToIndex:1];
      }];
      
      // result:
      // (
      //    F = Frank;
      //    J = Jim;
      //    B = Bob;
      // )
      

      ### linq_count

      - (NSUInteger) linq_count:(LINQCondition)condition;
      

      Counts the number of elements in an array that pass a given condition.

      As an example, you can check how many numbers equal a certain value:

      NSArray* input = @[@25, @35, @25];
      
      NSUInteger numbersEqualTo25 = [input linq_count:^BOOL(id item) {
          return [item isEqualToNumber:@25];
      }];
      // returns 2
      

      ### linq_concat

      - (NSArray*) linq_concat:(NSArray*)array;
      

      Returns an array which is the result of concatonating the given array to the end of this array.

      ### linq_reverse

      - (NSArray*) linq_reverse;
      

      Returns an array that has the same elements as the source but in reverse order.

      NSDictionary methods

      This section provides a few brief examples of each of the API methods.

      ### linq_where

      - (NSDictionary*) linq_where:(LINQKeyValueCondition)predicate;
      

      Filters a dictionary based on a predicate.

      The following example uses filters a dictionary to remove any keys that are equal to their value.

      NSDictionary* result = [input linq_where:^BOOL(id key, id value) {
         return [key isEqual:value];
      }];
      

      ### linq_select

      - (NSDictionary*) linq_select:(LINQKeyValueConditionKeyValueSelector)selector;
      

      Projects each key-value pair in a dictionary into a new form. Each key-value pair is transformed by a 'selector' into a new form, which is then used to populate the values of the output dictionary.

      The following example takes a dictionary which has string values, returning a new dictionary where each value is the first character of the source string.

      NSDictionary* result = [input linq_select:^id(id key, id value) {
          return [value substringToIndex:1];
      }];
      

      ### linq_toArray

      - (NSArray*) linq_toArray:(LINQKeyValueSelector)selector;
      

      Projects each key-value pair in a dictionary into a new form, which is used to populate the output array.

      The following example takes a dictionary which has string values, returning an array which concatenates the key and value for each item in the dictionary.

      NSDictionary* input = @{@A : @Apple, @B : @Banana, @C : @Carrot};
      
      NSArray* result = [input linq_toArray:^id(id key, id value) {
          return [NSString stringWithFormat:@%@, %@, key, value];
      }];
      
      // result:
      // (
      //    A, Apple,
      //    B, Banana,
      //    C, Carrot
      // )
      

      ### linq_any

      - (BOOL) linq_any:(LINQKeyValueCondition)condition;
      

      Tests whether any key-value pair in the dictionary passes the given condition.

      As an example, you can check whether value contains the letter 'n':

      NSDictionary* input = @{@a : @apple, @b : @banana, @c : @bat};
      
      BOOL anyValuesHaveTheLetterN = [input linq_any:^BOOL(id key, id value) {
          return [value rangeOfString:@n].length != 0;
      }];
      // returns YES
      

      ### linq_all

      - (BOOL) linq_all:(LINQKeyValueCondition)condition;
      

      Tests whether all the key-value pairs in the dictionary pass the given condition.

      As an example, you can check whether all values contains the letter 'a', or use the key component of the condition to see if each value contains the string key:

      NSDictionary* input = @{@a : @apple, @b : @banana, @c : @bat};
      
      BOOL allValuesHaveTheLetterA = [input linq_all:^BOOL(id key, id value) {
          return [value rangeOfString:@a].length != 0;
      }];
      // returns YES
      
      BOOL allValuesContainKey = [input linq_all:^BOOL(id key, id value) {
          return [value rangeOfString:key].length != 0;
      }];
      // returns NO - the value 'bat' does not contain the letter it is keyed with 'c'
      

      ### linq_count

      - (NSUInteger) linq_count:(LINQKeyValueCondition)condition;
      

      Counts the number of key-value pairs that satisfy the given condition.

      The following example counts how many dictionary values contain the key:

      NSDictionary* input = @{@a : @apple, @b : @banana, @c : @bat};
      
        NSUInteger valuesThatContainKey = [input linq_count:^BOOL(id key, id value) {
            return [value rangeOfString:key].length != 0;
        }];
        // returns 2 - bat does not contain the key c

    ### linq_merge

        - (NSDictionary*) linq_merge:(NSDictionary*)dic;

    Merges the contents of this dictionary with the given
    dictionary. For any duplicates, the value from the source
    dictionary will be used.

    The following example merges a pair of dictionaries

        NSDictionary* input = @{@a : @apple, @b : @banana, @c : @cat};

        NSDictionary* result = [input linq_merge:@{@d : @dog, @e : @elephant}];

        // result:
        // (
        //    a = apple;
        //    b = banana;
        //    c = cat;
        //    d = dog;
        //    e = elephant;
        // )

http://www.bkjia.com/IOSjc/940028.htmlwww.bkjia.comtruehttp://www.bkjia.com/IOSjc/940028.htmlTechArticle[IOS 开发] Linq数组排序 Linq To Objective-C 原文地址:www.Bkjia.com Bringing a Linq-style fluent query API to Objective-C. This project contains a collection of NSArray...

Quick start

1. Include the Tempo script
<script src="js/tempo.js" type="text/javascript"></script>
<script>Tempo.prepare("tweets").render(data);</script>
2. Compose the data template inline in HTML
<ol id="tweets">
    <li data-template>
        <img src="default.png" data-src="{{profile_image_url}}" />
        <h3>{{from_user}}</h3>
        <p>{{text}}, {{created_at|date 'HH:mm on EEEE'}}</p>
    </li>
    <li data-template-fallback>Sorry, JavaScript required!</li>
</ol>
3. Booyah! You're done!

Usage

You only need to include one little script:

<script src="js/tempo.js" type="text/javascript"></script>
Data

Tempo takes information encoded as JSON and renders it according to an HTML template. Below is a sample array of JSON data. Tempo can also iterate members of an associative array (object).

var data = [
    {'name':{'first':'Leonard','last':'Marx'},'nickname':'Chico','born':'March 21, 1887','actor': true,'solo_endeavours':[{'title':'Papa Romani'}]},
    {'name':{'first':'Adolph','last':'Marx'},'nickname':'Harpo','born':'November 23, 1888','actor':true,'solo_endeavours':[{'title':'Too Many Kisses','rating':'favourite'},{'title':'Stage Door Canteen'}]},
    {'name':{'first':'Julius Henry','last':'Marx'},'nickname':'Groucho','born': 'October 2, 1890','actor':true,'solo_endeavours':[{'title':'Copacabana'},{'title':'Mr. Music','rating':'favourite'},{'title':'Double Dynamite'}]},
    {'name':{'first':'Milton','last':'Marx'},'nickname':'Gummo','born':'October 23, 1892'},
    {'name':{'first':'Herbert','last':'Marx'},'nickname':'Zeppo','born':'February 25, 1901','actor':true,'solo_endeavours':[{'title':'A Kiss in the Dark'}]}
];
JavaScript
Tempo.prepare()

First you need to point Tempo at the container that contains the template elements:

var template = Tempo.prepare(element);
element

The ID of the HTML element (or the element itself) containing your data template. If you're using jQuery, you may pass in a jQuery object instead.

To initialize Tempo, run the prepare() function to scan an HTML container for data templates, cache them in memory, and remove the data template HTML elements from the page. Tempo.prepare(element) returns an instance of a renderer that knows how to layout the data you provide to it.

If the container does not contain a default (that is without conditions and not nested) data-template the entire contents of the container will be considered to represent the template.

template.render()
template.render(data);

The Tempo.prepare() function returns an instance of a template ready for rendering. Once the JSON data is available, run the render(data) function to add the data to the page.

data

The JSON data to be rendered - either an array or an object in which case the members are iterated and provided as key/value pairs.

template.append()

Renderer methods all return an instance of the renderer (a la fluent) so you can chain calls to it. The append(data) function will render the data you pass in and append it to the container.

Tempo.prepare('marx-brothers').render( data ).append( more_brothers );
template.prepend()

The prepend(data) function will render the data you pass in and insert it before others in the container.

Tempo.prepare('marx-brothers').render( data ).prepend( brothers_we_didnt_know_about );
template.clear()

The clear() function will empty the container, allowing you to e.g. render the data again.

Tempo.prepare('marx-brothers').render( data ).clear();
template.errors(errorHandler)

Tempo will attempt to deal with errors and failures silently but you can pass in your own handler for exceptions:

errorHandler

A function which will be called with the error object from the try/catch block.

Tempo.prepare('list').errors(function (err) {
    console.log('Whoa! something happened!');
    console.log(err);
}).render(data);
template.into(container)

The into(element) function will allow you to render the original template to one or more different containers specified. The method will return a new template on which you can call the other template methods such as render() or append().

container

The container to render the template to.

Render to different container:
Tempo.prepare('marx-brothers').into('alternative-container').render( data );
Reuse template for multiple different containers:
var template = Tempo.prepare('marx-brothers');
template.into('alternative-container').render( data_1 );
template.into('yet-another-alternative-container').render( data_2 );
HTML
data-template

Any tag with the data-template attribute will be treated as a template. For compliance the full (non-minimized) form is also supported: data-template="data-template".

{{field}}

Any field represented in the JSON data may be retrieved by referencing the field name inside double brackets.

<ol id="marx-brothers">
    <li data-template>{{nickname}} {{name.last}}</li>
</ol>

The example above would produce the following output:

1. Chico Marx
2. Harpo Marx
3. Groucho Marx
4. Gummo Marx
5. Zeppo Marx

Here's an example of a simple array of strings:

var data = [ 'Leonard Marx', 'Adolph Marx', 'Julius Henry Marx', 'Milton Marx', 'Herbert Marx' ];

You can reference the object being iterated with {{.}}:

<ol id="marx-brothers">
    <li data-template>{{.}}</li>
</ol>

If the JSON data represents an array of arrays (which can not be referenced by field/member name) for example:

var data = [ ['Leonard','Marx'], ['Adolph','Marx'], ['Julius Henry','Marx'], ['Milton','Marx'], ['Herbert','Marx'] ];

You can reference array elements with the following notation:

<ol id="marx-brothers">
    <li data-template>{{[0]}} {{[1]}}</li>
</ol>

Both examples would produce the following output:

1. Leonard Marx
2. Adolph Marx
3. Julius Henry Marx
4. Milton Marx
5. Herbert Marx
Using data from associative arrays (objects)

Normally data being iterated is represented as an array of objects. In some cases however the data is a series of objects in a map:

var data = {
    'leonard': 'Leonard Marx',
    'adolph': 'Adolph Marx',
    'julius': 'Julius Henry Marx',
    'milton': 'Milton Marx',
    'herbert': Herbert Marx'
};

In this case you can iterate all the elements using the data-from-map attribute where the key name can be accessed with {{key}} and the value object via {{value}}:

<ol id="list">
    <li data-template data-from-map>{{value}} - {{key | append '@marx.com'}}</li>
</ol>
Values are escaped by default

All values are escaped by default. To disable automatic escaping pass in the 'escape': false parameter:

Tempo.prepare('marx-brothers', {'escape': false}).render(data);

If you disable escaping you can control this at individual value level using the escape and encodeURI filters.

Nested data-templates

Data templates can even be nested within other data templates. Multiple nested templates are supported.

<li data-template>
    {{nickname}} {{name.last}}
    <ul>
        <li data-template-for="solo_endeavours">{{title}}</li>
    </ul>
</li>

The example above would produce the following output:

1. Chico Marx
    ◦ Papa Romani
2. Harpo Marx
    ◦ Too Many Kisses
    ◦ Stage Door Canteen
3. Groucho Marx
    ◦ Copacabana
    ◦ Mr. Music
    ◦ Double Dynamite
4. Gummo Marx
5. Zeppo Marx
    ◦ A Kiss in the Dark

You can (recursively) refer to parent objects within a nested template using the _parent variable.

<li data-template-for="solo_endeavours">{{_parent.name.first}} acted in {{title}}</li>
Nested Templates as Partial Template Files

Tempo supports separating more complex nested templates in to master and partial template files. Partials templates are loaded on demand from the server and do require you to use the alternative asynchronous pattern:

JavaScript:
Tempo.prepare('marx-brothers', {}, function(template) {
   template.render(data);
});
Template:
<li data-template>
    {{name.first}} {{name.last}}
    <ol>
        <li data-template-for="solo_endeavours" data-template-file="partials/movie.html"></li>
    </ol>
</li>
Partial ('partials/movie.html'):
{{title}}

This would produce the same output as the example above:

1. Chico Marx
    ◦ Papa Romani
2. Harpo Marx
    ◦ Too Many Kisses
    ◦ Stage Door Canteen
3. Groucho Marx
    ◦ Copacabana
    ◦ Mr. Music
    ◦ Double Dynamite
4. Gummo Marx
5. Zeppo Marx
    ◦ A Kiss in the Dark
Conditional Templates

Tempo provides boolean and value-based conditionals, as well as the ability to define multiple data templates per container (the first matching template wins).

<ul id="marx-brothers3">
    <li data-template data-if-nickname="Groucho"">{{nickname}} (aka {{name.first}}) was grumpy!</li>
    <li data-template data-if-actor>{{name.first}}, nicknamed '<i>{{nickname}} {{name.last}}</i>' was born on {{born}}</li>

    <!-- Default template -->
    <li data-template>{{name.first}} {{name.last}} was not in any movies!</li>
</ul>

This example would produce the following output:

• Leonard, nicknamed 'Chico Marx' was born on March 21, 1887
• Adolph, nicknamed 'Harpo Marx' was born on November 23, 1888
• Groucho (aka Julius Henry) was grumpy!
• Milton Marx was not in any movies!
• Herbert, nicknamed 'Zeppo Marx' was born on February 25, 1901

You can define templates based on data member existence as well:

<li data-template data-has="friend">{{friend}}></li>

本文由皇牌天下投注网发布于计算机教程,转载请注明出处:[IOS 开发] Linq数组排序

关键词:

最火资讯