Relative complement of two lists where the elements are of different types - linq

I'm looking to remove all elements in a list that can be compared to elements of another list of a different type that don't share a common inheretence, but I do have an equality function for. An example might make it clearer:
given the scaffolding
bool isSomeSortOfEqual(Bottle b, Printer p){
//implementation
}
List<Bottle> bottles = getBottles();
List<Printer> printers = getPrinters();
I would like to do something like this:
List<Bottle> result = bottles.Except(printers, (b, p => isSomeSortOfEqual(b, p));
Are there any builtins for this in .NET, or should I implement this by hand? None of the questions relating to relative complement or except in .NET on stackoverflow seem to deal with having different types.

How about this? The basic idea is to cast the lists to List<object> and then use .Except with an IEqualityComparer<object>
class A
{
public int Ai;
}
class B
{
public int Bi;
}
public class ABComparer : IEqualityComparer<object>
{
public bool Equals(object x, object y)
{
A isA = x as A ?? y as A;
B isB = x as B ?? y as B;
if (isA == null || isB == null)
return false;
return isA.Ai == isB.Bi;
}
public int GetHashCode(object obj)
{
A isA = obj as A;
if (isA != null)
return isA.Ai;
B isB = obj as B;
if (isB != null)
return isB.Bi;
return obj.GetHashCode();
}
}
class Program
{
static void Main(string[] args)
{
List<object> As = new List<object> { new A { Ai = 1 }, new A { Ai = 2 }, new A { Ai = 3 } };
List<object> Bs = new List<object> { new B { Bi = 1 }, new B { Bi = 1 } };
var except = As.Except(Bs, new ABComparer()).ToArray();
// Will give two As with Ai = 2 and Ai = 3
}
}

not any matches?
from b in bottles
where !printers.Any(p => isSomeSortOfEqual(b, p))
select b;

Related

Is it necessary to distinguish 3 state fields when doing breadth first search

In the CTCI solution for checking to see if there is a route between two nodes, a 3 state enum is defined. However, it appears that what is really important is a binary state of (visited = true|false). Is this true? If not, why is it necessary to distinguish between 3 separate states?
public enum State {
Unvisited, Visited, Visiting;
}
public static boolean search(Graph g,Node start,Node end) {
LinkedList<Node> q = new LinkedList<Node>();
for (Node u : g.getNodes()) {
u.state = State.Unvisited;
}
start.state = State.Visiting;
q.add(start);
Node u;
while(!q.isEmpty()) {
u = q.removeFirst();
if (u != null) {
for (Node v : u.getAdjacent()) {
if (v.state == State.Unvisited) {
if (v == end) {
return true;
} else {
v.state = State.Visiting;
q.add(v);
}
}
}
u.state = State.Visited;
}
}
return false;
}

Linq query filter with "contains" with list<T> multiple elements

I want to query a list by Linq but filter by an other list containing two elements ( Name, Status) in my example.
This is inspired by an old question I've adapted to my issue.
LINQ: "contains" and a Lambda query
(in this answer it's working for only one element i.e. Status)
I try to use the "contains" method but didn't succeed to filter my list.
I should obtain a result with only two buildings (two, five)
Has anyone an idea where I'm stopped ?
Thanks
Blockquote
public class Building
{
public enum StatusType
{
open,
closed,
weird,
};
public string Name { get; set; }
public StatusType Status { get; set; }
}
private static readonly List<Building> BuildingList = new List<Building>()
{
new Building() {Name = "one", Status = Building.StatusType.open},
new Building() {Name = "two", Status = Building.StatusType.closed},
new Building() {Name = "three", Status = Building.StatusType.weird},
new Building() {Name = "four", Status = Building.StatusType.open},
new Building() {Name = "five", Status = Building.StatusType.closed},
new Building() {Name = "six", Status = Building.StatusType.weird},
};
private void GetResult()
{
var buildingSelect = new List<Building>
{
new Building() {Name = "two", Status = Building.StatusType.closed},
new Building() {Name = "five", Status = Building.StatusType.closed}
};
var q = (from building in BuildingList
where buildingSelect.Contains(building.Name, building.Status)
select building).ToList();
dataGridView1.DataSource = q;
}
The main problem of your LINQ is that you are trying the compare the equality of two Buildings, which LINQ can only compare by their references because Building does not implement IEquatable<Building> nor override object.Equals.
One way to solve it is to manually specify which properties to compare for equality as per #Wayne's answer.
The other way is, if Building instances are meant to be equated by their values and not by their references, implement IEquatable<Building> and override object.Equals:
public class Building : IEquatable<Building>
{
public Building(string name, StatusType status)
{
Name = name;
Status = status;
}
public enum StatusType
{
open,
closed,
weird,
};
public string Name { get; }
public StatusType Status { get; }
public static bool operator ==(Building left, Building right)
=> Equals(left, right);
public static bool operator !=(Building left, Building right)
=> !Equals(left, right);
public override bool Equals(object obj) => Equals(obj as Building);
public bool Equals(Building other)
{
if (ReferenceEquals(this, other))
{
return true;
}
if (ReferenceEquals(other, null) || GetType() != other.GetType())
{
return false;
}
return Name == other.Name && Status == other.Status;
}
public override int GetHashCode()
{
unchecked
{
int hash = 17;
hash = hash * 23 + Name?.GetHashCode() ?? 0;
hash = hash * 23 + Status.GetHashCode();
return hash;
}
}
}
That way, your original code would work because List.Contains will now use your implementation of IEquatable<Building> to check for equality.
You mean something like this?
var q = from b in BuildingList
from bs in buildingSelect
where b.Name == bs.Name && b.Status == bs.Status
select b;
or perhaps:
var q = from b in BuildingList
join bs in buildingSelect
on new { b.Name, b.Status } equals new { bs.Name, bs.Status }
select b;
You can either override the equality in the class itself, IF this makes sense.
Or just make the check normally with Any(), like this:
var q = (from building in BuildingList
where buildingSelect.Any(b => b.Name == building.Name
&& b.Status == building.Status)
select building).ToList();

Generating all the elements of a power set

Power set is just set of all subsets for given set.
It includes all subsets (with empty set).
It's well-known that there are 2^N elements in this set, where N is count of elements in original set.
To build power set, following thing can be used:
Create a loop, which iterates all integers from 0 till 2^N-1
Proceed to binary representation for each integer
Each binary representation is a set of N bits (for lesser numbers, add leading zeros).
Each bit corresponds, if the certain set member is included in current subset.
import java.util.NoSuchElementException;
import java.util.BitSet;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
public class PowerSet<E> implements Iterator<Set<E>>, Iterable<Set<E>> {
private final E[] ary;
private final int subsets;
private int i;
public PowerSet(Set<E> set) {
ary = (E[])set.toArray();
subsets = (int)Math.pow(2, ary.length) - 1;
}
public Iterator<Set<E>> iterator() {
return this;
}
#Override
public void remove() {
throw new UnsupportedOperationException("Cannot remove()!");
}
#Override
public boolean hasNext() {
return i++ < subsets;
}
#Override
public Set<E> next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
Set<E> subset = new TreeSet<E>();
BitSet bitSet = BitSet.valueOf(new long[] { i });
if (bitSet.cardinality() == 0) {
return subset;
}
for (int e = bitSet.nextSetBit(0); e != -1; e = bitSet.nextSetBit(e + 1)) {
subset.add(ary[e]);
}
return subset;
}
// Unit Test
public static void main(String[] args) {
Set<Integer> numbers = new TreeSet<Integer>();
for (int i = 1; i < 4; i++) {
numbers.add(i);
}
PowerSet<Integer> pSet = new PowerSet<Integer>(numbers);
for (Set<Integer> subset : pSet) {
System.out.println(subset);
}
}
}
The output I am getting is:
[2]
[3]
[2, 3]
java.util.NoSuchElementException
at PowerSet.next(PowerSet.java:47)
at PowerSet.next(PowerSet.java:20)
at PowerSet.main(PowerSet.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at edu.rice.cs.drjava.model.compiler.JavacCompiler.runCommand(JavacCompiler.java:272)
So, the problems are:
I am got getting all the elements(debugging shows me next is called only for even i's).
The exception should not have been thrown.
The problem is in your hasNext. You have i++ < subsets there. What happens is that since hasNext is called once from next() and once more during the iteration for (Set<Integer> subset : pSet) you increment i by 2 each time. You can see this since
for (Set<Integer> subset : pSet) {
}
is actually equivalent to:
Iterator<PowerSet> it = pSet.iterator();
while (it.hasNext()) {
Set<Integer> subset = it.next();
}
Also note that
if (bitSet.cardinality() == 0) {
return subset;
}
is redundant. Try instead:
#Override
public boolean hasNext() {
return i <= subsets;
}
#Override
public Set<E> next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
Set<E> subset = new TreeSet<E>();
BitSet bitSet = BitSet.valueOf(new long[] { i });
for (int e = bitSet.nextSetBit(0); e != -1; e = bitSet.nextSetBit(e + 1)) {
subset.add(ary[e]);
}
i++;
return subset;
}

BASH brace expansion algorithm

I am stuck on this algorithmic question :
design an algorithm that parse an expression like this :
"((a,b,cy)n,m)" should give :
an - bn - cyn - m
The expression can nest, therefore :
"((a,b)o(m,n)p,b)" parses to ;
aomp - aonp - bomp - bonp - b.
I thought of using stacks, but it is too complicated.
thanks.
You can parse it with a Recursive Descent Parser.
Let's say the comma separated strings are components, so for an expression ((a, b, cy)n, m), (a, b, cy)n and m are two components. a, b and cy are also components. So this is a recursive definition.
For a component (a, b, cy)n, let's say (a, b, cy) and n are two component parts of the component. Component parts will later be combined to produce final result (i.e., an - bn - cyn).
Let's say an expression is comma separated components, for example, (a, cy)n, m is an expression. It has two components (a, cy)n and m, and the component (a, cy)n has two component parts (a, cy) and n, and component part (a, cy) is a brace expression containing a nested expression: a, cy, which also has two components a and cy.
With these definitions (you might use other terms), we can write down the grammar for your expression:
expression = component, component, ...
component = component_part component_part ...
component_part = letters | (expression)
One line is one grammar rule. The first line means an expression is a list of comma separated components. The second line means a component can be constructed with one or more component parts. The third line means a component part can be either a continuous sequence of letters or a nested expression inside a pair of braces.
Then you can use a Recursive Descent Parser to solve your problem with the above grammar.
We will define one method/function for each grammar rule. So basically we will have three methods ParseExpression, ParseComponent, ParseComponentPart.
Algorithm
As I stated above, an expression is comma separated components, so in our ParseExpression method, it simply calls ParseComponent, and then check if the next char is comma or not, like this (I'm using C#, I think you can easily convert it to other languages):
private List<string> ParseExpression()
{
var result = new List<string>();
while (!Eof())
{
// Parsing a component will produce a list of strings,
// they are added to the final string list
var items = ParseComponent();
result.AddRange(items);
// If next char is ',' simply skip it and parse next component
if (Peek() == ',')
{
// Skip comma
ReadNextChar();
}
else
{
break;
}
}
return result;
}
You can see that, when we are parsing an expression, we recursively call ParseComponent (it will then recursively call ParseComponentPart). It's a top-down approach, that's why it's called Recursive Descent Parsing.
ParseComponent is similar, like this:
private List<string> ParseComponent()
{
List<string> leftItems = null;
while (!Eof())
{
// Parse a component part will produce a list of strings (rightItems)
// We need to combine already parsed string list (leftItems) in this component
// with the newly parsed 'rightItems'
var rightItems = ParseComponentPart();
if (rightItems == null)
{
// No more parts, return current result (leftItems) to the caller
break;
}
if (leftItems == null)
{
leftItems = rightItems;
}
else
{
leftItems = Combine(leftItems, rightItems);
}
}
return leftItems;
}
The combine method simply combines two string list:
// Combine two lists of strings and return the combined string list
private List<string> Combine(List<string> leftItems, List<string> rightItems)
{
var result = new List<string>();
foreach (var leftItem in leftItems)
{
foreach (var rightItem in rightItems)
{
result.Add(leftItem + rightItem);
}
}
return result;
}
Then is the ParseComponentPart:
private List<string> ParseComponentPart()
{
var nextChar = Peek();
if (nextChar == '(')
{
// Skip '('
ReadNextChar();
// Recursively parse the inner expression
var items = ParseExpression();
// Skip ')'
ReadNextChar();
return items;
}
else if (char.IsLetter(nextChar))
{
var letters = ReadLetters();
return new List<string> { letters };
}
else
{
// Fail to parse a part, it means a component is ended
return null;
}
}
Full Source Code (C#)
The other parts are mostly helper methods, full C# source code is listed below:
using System;
using System.Collections.Generic;
using System.Text;
namespace Examples
{
public class BashBraceParser
{
private string _expression;
private int _nextCharIndex;
/// <summary>
/// Parse the specified BASH brace expression and return the result string list.
/// </summary>
public IList<string> Parse(string expression)
{
_expression = expression;
_nextCharIndex = 0;
return ParseExpression();
}
private List<string> ParseExpression()
{
// ** This part is already posted above **
}
private List<string> ParseComponent()
{
// ** This part is already posted above **
}
private List<string> ParseComponentPart()
{
// ** This part is already posted above **
}
// Combine two lists of strings and return the combined string list
private List<string> Combine(List<string> leftItems, List<string> rightItems)
{
// ** This part is already posted above **
}
// Peek next char without moving the cursor
private char Peek()
{
if (Eof())
{
return '\0';
}
return _expression[_nextCharIndex];
}
// Read next char and move the cursor to next char
private char ReadNextChar()
{
return _expression[_nextCharIndex++];
}
private void UnreadChar()
{
_nextCharIndex--;
}
// Check if the whole expression string is scanned.
private bool Eof()
{
return _nextCharIndex == _expression.Length;
}
// Read a continuous sequence of letters.
private string ReadLetters()
{
if (!char.IsLetter(Peek()))
{
return null;
}
var str = new StringBuilder();
while (!Eof())
{
var ch = ReadNextChar();
if (char.IsLetter(ch))
{
str.Append(ch);
}
else
{
UnreadChar();
break;
}
}
return str.ToString();
}
}
}
Use The Code
var parser = new BashBraceParser();
var result = parser.Parse("((a,b)o(m,n)p,b)");
var output = String.Join(" - ", result);
// Result: aomp - aonp - bomp - bonp - b
Console.WriteLine(output);
public class BASHBraceExpansion {
public static ArrayList<StringBuilder> parse_bash(String expression, WrapperInt p) {
ArrayList<StringBuilder> elements = new ArrayList<StringBuilder>();
ArrayList<StringBuilder> result = new ArrayList<StringBuilder>();
elements.add(new StringBuilder(""));
while(p.index < expression.length())
{
if (expression.charAt(p.index) == '(')
{
p.advance();
ArrayList<StringBuilder> temp = parse_bash(expression, p);
ArrayList<StringBuilder> newElements = new ArrayList<StringBuilder>();
for(StringBuilder e : elements)
{
for(StringBuilder t : temp)
{
StringBuilder s = new StringBuilder(e);
newElements.add(s.append(t));
}
}
System.out.println("elements :");
elements = newElements;
}
else if (expression.charAt(p.index) == ',')
{
result.addAll(elements);
elements.clear();
elements.add(new StringBuilder(""));
p.advance();
}
else if (expression.charAt(p.index) == ')')
{
p.advance();
result.addAll(elements);
return result;
}
else
{
for(StringBuilder sb : elements)
{
sb.append(expression.charAt(p.index));
}
p.advance();
}
}
return elements;
}
public static void print(ArrayList<StringBuilder> list)
{
for(StringBuilder s : list)
{
System.out.print(s + " * ");
}
System.out.println();
}
public static void main(String[] args) {
WrapperInt p = new WrapperInt();
ArrayList<StringBuilder> list = parse_bash("((a,b)o(m,n)p,b)", p);
//ArrayList<StringBuilder> list = parse_bash("(a,b)", p);
WrapperInt q = new WrapperInt();
ArrayList<StringBuilder> list1 = parse_bash("((a,b,cy)n,m)", q);
ArrayList<StringBuilder> list2 = parse_bash("((a,b)dr(f,g)(k,m),L(p,q))", new WrapperInt());
System.out.println("*****RESULT : ******");
print(list);
print(list1);
print(list2);
}
}
public class WrapperInt {
public WrapperInt() {
index = 0;
}
public int advance()
{
index ++;
return index;
}
public int index;
}
// aomp - aonp - bomp - bonp - b.

Flatten LINQ collection object with nested object collections

This is a tricky one. I an trying to flatten a LINQ object collection. Each item in the collection has the potential of having two collections of other objects. See the example below.
public class DemoClass
{
public string Name {get; set;}
public string Address {get; set;}
public List<Foo> Foos = new List<Foo>();
public List<Bar> Bars = new List<Bars>();
}
What I had been doing is this using this code block to flatten this object
var output = from d in DemoClassCollection
from f in d.Foos
from b in d.Bars
select new {
d.Name,
d.Address,
f.FooField1,
f.FooField2,
b.BarField1,
b.BarField2
};
But the problem I'm having is that the result I get is only those DemoClass objects that have objects in the Foos and Bars collections. I need to get all objects in the DemoClass regardless if there are objects in the Foos and Bars collections.
Any help would be greatly appreciated.
Thanks!
Sounds like you might want to use DefaultIfEmpty:
var output = from d in DemoClassCollection
from f in d.Foos.DefaultIfEmpty()
from b in d.Bars.DefaultIfEmpty()
select new {
d.Name,
d.Address,
FooField1 = f == null ? null : f.FooField1,
FooField2 = f == null ? null : f.FooField2,
BarField1 = b == null ? null : b.BarField1,
BarField2 = b == null ? null : b.BarField2
};
Looks like a left outer join in Linq will work (http://msdn.microsoft.com/en-us/library/bb397895.aspx
var output = from d in DemoClassCollection
from f in d.Foos.DefaultIfEmpty()
from b in d.Bars.DefaultIfEmpty()
select new {
d.Name,
d.Address,
f.FooField1,
f.FooField2,
b.BarField1,
b.BarField2
};
I believe you can implement an IComparer to perform custom JOINS or UNIONS in linq based on how you implement the CompareTo() method
From MSDN: http://msdn.microsoft.com/en-us/library/system.icomparable.aspx
using System;
using System.Collections;
public class Temperature : IComparable
{
// The temperature value
protected double temperatureF;
public int CompareTo(object obj) {
if (obj == null) return 1;
Temperature otherTemperature = obj as Temperature;
if (otherTemperature != null)
return this.temperatureF.CompareTo(otherTemperature.temperatureF);
else
throw new ArgumentException("Object is not a Temperature");
}
public double Fahrenheit
{
get
{
return this.temperatureF;
}
set {
this.temperatureF = value;
}
}
public double Celsius
{
get
{
return (this.temperatureF - 32) * (5.0/9);
}
set
{
this.temperatureF = (value * 9.0/5) + 32;
}
}
}
public class CompareTemperatures
{
public static void Main()
{
ArrayList temperatures = new ArrayList();
// Initialize random number generator.
Random rnd = new Random();
// Generate 10 temperatures between 0 and 100 randomly.
for (int ctr = 1; ctr <= 10; ctr++)
{
int degrees = rnd.Next(0, 100);
Temperature temp = new Temperature();
temp.Fahrenheit = degrees;
temperatures.Add(temp);
}
// Sort ArrayList.
temperatures.Sort();
foreach (Temperature temp in temperatures)
Console.WriteLine(temp.Fahrenheit);
}
}
// The example displays the following output to the console (individual
// values may vary because they are randomly generated):
// 2
// 7
// 16
// 17
// 31
// 37
// 58
// 66
// 72
// 95

Resources