Select() from Linq in Swift 3.0

Select() from LINQ in swift 3.0?

map(_:)

let ranks = cards.map{ $0.Rank }

which is syntactic sugar for:

let ranks = cards.map({ (card: Card) -> Rank in
return card.rank
})

The applied syntactic sugar includes:

  1. Trailing closure syntax

    let ranks = cards.map { (card: Card) -> Rank in
    return card.rank
    }
  2. Argument type inference

    let ranks = cards.map { card -> Rank in
    return card.rank
    }
  3. Return type inference

    let ranks = cards.map { card in
    return card.rank
    }
  4. Implicit return value

    let ranks = cards.map { card in
    card.rank
    }
  5. Anonymous closure arguments

    let ranks = cards.map { $0.rank }

Check out the language guide section on closures (the Swift name for what C# calls lambdas) for more information,

Is something in Swift like LINQ in C#

Swift incorporates several of the features that are bundled together in .net as LINQ, though possibly not in quite an out-of-the-box sense.

Anonymous types are quite close to tuples with named values in Swift.

In C#:

   var person = new { firstName = "John", lastName = "Smith" };
Console.WriteLine(person.lastName);

Output: Smith

In Swift:

var person = (firstName: "John", lastName: "Smith")
person.firstName = "Fred"
print(person.lastName)

Output: Smith

LINQ queries are of course very powerful/expressive, but you can replicate a large portion of what they do using map, filter and reduce in Swift. With lazy, you can get the same functionality where you create an object that can be looped over ahead of time, and only evaluate it when the looping actually happens:

In C#:

var results =
SomeCollection
.Where(c => c.SomeProperty < 10)
.Select(c => new {c.SomeProperty, c.OtherProperty});

foreach (var result in results)
{
Console.WriteLine(result.ToString());
}

In Swift:

// just so you can try this out in a playground...
let someCollection = [(someProperty: 8, otherProperty: "hello", thirdProperty: "foo")]

let results =
someCollection.lazy
.filter { c in c.someProperty < 10 }
// or instead of "c in", you can use $0:
.map { ($0.someProperty, $0.otherProperty) }

for result in results {
print(result)
}

Swift generics make writing operations similar to existing LINQ functionality quite straightforward. For example, from the LINQ wikipedia article:

Count
The Count operator counts the number of elements in the given collection. An overload taking a predicate, counts the number of elements matching the predicate.

Could be written in Swift like this (2.0 protocol extension syntax):

extension SequenceType {
// overload for count that takes a predicate
func count(match: Generator.Element -> Bool) -> Int {
return reduce(0) { n, elem in match(elem) ? n + 1 : n }
}
}

// example usage
let isEven = { $0 % 2 == 0 }

[1,1,2,4].count(isEven) // returns 2

You could also overload it to take a particular element to count if the element conforms to Equatable:

extension SequenceType where Generator.Element: Equatable {
// overload for count that takes a predicate
func count(element: Generator.Element) -> Int {
return count { $0 == element }
}
}

[1,1,2,4].count(1)

Structs by default have object-initializer-like syntax:

struct Person { let name: String; let age: Int; }

let person = Person(name: "Fred Bloggs", age: 37)

and via ArrayLiteralConvertible, any collection type can have similar syntax to collection initializer syntax:

let list: MyListImplementation = [1,2,3,4]

Linq to select data from one table not in other table

First, could you update your question with the entire method so that we can see what might be going on with the ViewBag? Because your code should work just fine, assigning whatever value to the ViewBag is no problem normally:

    ViewBag.property1 = 0;
ViewBag.property1 = "zero";

works just fine. ViewBag is dynamic. Now, you could get that error if you would later try to assing ViewBag.ddlUserId to something that actually is the wrong type.

I would like you to rewrite your statement as well, let me explain why. Assume for a moment that you have a lot ( > 100.000) of User records in your db.Users and we assume the same for Fi as well. In your code, result1 and result2 are now two lists, one containing >100.000 User objects and the other >100.000 Fi objects. Then these two lists are compared to each other to produce a list of strings. Now imagine the resource required for your web server to process this. Under the assumption that your actually using/accessing a separate SQL server to retrieve your data from, it would be a lot better and faster to let that server do the work, i.e. producing the list of UserID's.
For that you'd either use Kirill Bestemyanov's answer or the following:

    var list = (from user in db.Users
where !db.Fi.Any(f => f.UserID == user.UserID)
select user.UserName).ToList()

This will produce just one query for the SQL server to execute:

    SELECT 
[Extent1].[UserName] AS [UserName]
FROM [dbo].[Users] AS [Extent1]
WHERE NOT EXISTS (SELECT
1 AS [C1]
FROM [dbo].[Fi] AS [Extent2]
WHERE [Extent2].[UserID] = [Extent1].[UserID]
)}

which in the end is what you want...

Just to clarify more:

    var list = (from user in db.Users
where !db.Fi.Any(f => f.UserID == user.UserID)
select user.UserName).ToList()

can be written as the following lambda expression as well:

    var list = db.Users.Where(user => !db.Fi.Any(f => f.UserID == user.UserID))
.Select(user => user.UserName).ToList()

which from the looks of it is slightly different from Kirill Bestemyanov's answer (which I slightly modified, just to make it look more similar):

    var list = db.Users.Where(user => !db.Fi.Select(f => f.UserID)
.Contains(user.UserID))
.Select(user => user.UserName).ToList();

But, they will in fact produce the same SQL Statement, thus the same list.

Does Select followed by Where result in two iterations over the IEnumerable?

There is a single iteration over the collection performed when you call the .ToArray method so both should be equivalent. .Select is a projection and .Where is a filter, both expressed as expression trees on the original dataset.

Could be easily proven:

public class Foo: IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
yield return 1;
Console.WriteLine("we are at element 1");
yield return 2;
Console.WriteLine("we are at element 2");
yield return 3;
Console.WriteLine("we are at element 3");
}

System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}

class Program
{
static void Main()
{
var filtered = new Foo()
.Select(item => item * 10)
.Where(item => item < 20)
.ToList();
}
}

when run prints the following:

we are at element 1
we are at element 2
we are at element 3

LINQ sorting by number of appearances

var resunt = from c in db.Letters
group c by c.letter into p
orderby p.Count() descending
select p.Key;

When you use GroupBy you get an IGroupping object that contains a property of the Key object that you've grouped by and a collection of the values in the group. In your case you want to return the Key - the c.letter

Sort linq query result, when it has First() and into Group

You can order the group before selecting the first record:

var qryLatestInterview = from rows in dt.AsEnumerable()
group rows by new
{
PositionID = rows["msbf_acc_cd"],
CandidateID = rows["msbf_fac_tp"],
} into grp
select grp.OrderBy(x=> x["msbf_fac_dt"]).First();

Parameters after opening bracket

This is called trailing closure syntax.

I give a nice rundown of the various syntactic sugars of closures in this answer.

The expanded version of this code would be:

app.get("welcome", { (request: Request) throws -> ResponseRepresentable in 
return "Hello"
})

how to understand add new instance methods by extentions from apple's guidebook?

If you want to pass printHello then you do it like this:

3.repetitions(task: printHello)

This way uses trailing closure syntax:

3.repetitions {
print("Hello!")
}

It is syntactic sugar for this:

3.repetitions(task: {
print("Hello!")
})

map high order function format in swift

You are using the following Dictionary initializer:

init<S>(_ keysAndValues: S, uniquingKeysWith combine: (Dictionary<Key, Value>.Value, Dictionary<Key, Value>.Value) throws -> Dictionary<Key, Value>.Value) rethrows where S : Sequence, S.Element == (Key, Value)

Note that S is a sequence where its elements are a tuple of key/value pairs.

When you pass nums1.map{ ($0, 1) } to the first parameter, you are creating an array of key/value tuples from nums1.

It fails when you use nums2.map{ $0, 1 } because that is missing the parentheses for the tuple.

Keep in mind that nums1.map{ ($0, 1) } is shorthand for nums1.map({ ($0, 1) }). That's all related to trailing closures which has nothing to do with the parentheses for the tuple that appear inside the { }.



Related Topics



Leave a reply



Submit