Left Join LINQ and using Bitwise Comparisons.
I have a problem that can be described as (thanks to David B for clarifying this):
The goal is to return 1 row per OID from the Left Table, where the Count of the records in the left table is equal to the Count of the matching rows in the right table. A record matches when the OID, RID, and the FLAG is set in FLAGS for a row.
The Objects we are comparing have the following structure:
public class Roads : List<Road>{}
public class Road
{
public int RID;
public int OID;
public int Check = 1;
public long Flag;
}
public class Cars : List<Car> { }
public class Car
{
public int RID;
public int OID;
public long Flags;
}
The objects a filled with the following data.
Roads rs = new Roads();
Cars cs = new Cars();
Car c = new Car();
c.OID = 1;
c.RID = 1;
c.Flags = 31; // 11111
cs.Add(c);
c = new Car();
c.OID = 1;
c.RID = 2;
c.Flags = 31; //11111
cs.Add(c);
c = new Car();
c.OID = 1;
c.RID = 3;
c.Flags = 4; //00100
cs.Add(c);
Road r = new Road();
r.OID = 1;
r.RID = 1;
r.Flag = 8; //00010
rs.Add(r);
r = new Road();
r.OID = 1;
r.RID = 2;
r.Flag = 2; //01000
rs.Add(r);
r = new Road();
r.OID = 1;
r.RID = 3;
r.Flag = 4; //01000
rs.Add(r);
// r = new Road();
// r.OID = 1;
// r.RID = 3;
// r.Flag = 16; //00001
// rs.Add(r);
To see if a flag is set you do a bitwise comparison, i.e. cs[0].Flags && rs[0].Flag > 0 is TRUE, cs[0].Flags & rs[0].Flag = 0 is FALSE
I have this general query that will get me the rows where the count of OID in cs = the count of matching OID in rs. I need a modified query now where the rest of the rules are applied. Where we check if the Flag is in the Flag for the specific row match.
var carLookup = cs.ToLookup(cb => c.OID);
var roadLookup = rs.ToLookup(rb => r.OID);
var results1 = from x in carLookup
let carCount = x.Count()
let roadCount = roadLookup[x.Key].Count()
where carCount == roadCount
select new { OID = x.Key, CarCount = carCount, RoadCount = roadCount };
How can I extend this to get the additional filter conditions applied? What I am struggling with is having columns available where I need them to build the proper filter conditions. For example, I need to compare Flags && Flag. But how do I get so I have access to Flag and Flags to do the additional filter?
To Expand. I work mostly with TSQL, so I'm trying to mimic a logic flow I can easily apply in TSQL. If I was doing this with TSQL, it would look like this (note special case for 0):
SELECT cs.OID, Count(cs.OID) AS CarCount, Sum(RS.Check) AS RoadCount
FROM Cars AS cs
LEFT JOIN Roads AS RS
ON CS.oid = RS.OID
AND cs.RID = RS.RID
AND (CS.FLAGS & RS.FLAG > 0
OR (CS.FLAGS=0 AND RS.FLAG=0))
GROUP BY cs.OID
HAVING Count(cs.OID) = Sum(RS.Check)
With that statement, and the data above, the result would be
1, 3, 3.
If I were to comment the last add to Roads, and uncomment the next line, changing the Flag to 16, then the result would be:
NULL
Please comment if you need more info.
I think this should be equivalent to your SQL statement, however it didn't produce the result you mentioned since your SQL uses RS.Check but you didn't assign any Check values in your sample code (you used r.OID). I went ahead and added r.Check = 1; to each Road object and was able to get the result you mentioned.
var query = from car in cs
from road in rs
where car.OID == road.OID
&& car.RID == road.RID
&& ((car.Flags & road.Flag) > 0 || (car.Flags == 0 && road.Flag == 0))
group new { car, road } by car.OID into grouping
let CarCount = grouping.Count()
let RoadCount = grouping.Sum(o => o.road.Check)
where CarCount == RoadCount
select new { OID = grouping.Key, CarCount, RoadCount };
Related
I'm trying to select 2 random items out of a list using the RNG class. The problem is occasionally I get the same 2 numbers and I'd like them to be unique. I tried using a while loop to get another number if the it's the same as the last one but adding even a simple while loop results in an "Exceeded prepaid gas" error. What am I not understanding?
//simplified for posting question
var lengthOfList = 10
var numItemsWanted = 2
//Get more rng numbers than I need incase of duplicates
const rng = new RNG<u32>(lenghtOfList, lengthOfList)
for(let i = 0; i < numItemsWanted; i++) {
var r = rng.next()
while (r == rng.last()) {
r = rng.next()
}
newList.push(oldList[r])
}
Working:
//simplified for posting question
var lengthOfList = 10
var numItemsWanted = 2
//Get more rng numbers than I need incase of duplicates
const rng = new RNG<u32>(lenghtOfList, lengthOfList)
let r = rng.next()
let last = r + 1
for(let i = 0; i < numItemsWanted; i++) {
newList.push(oldList[r])
last = r
r = rng.next()
while (r == last) {
r = rng.next()
}
}
this is about near-sdk-as, the smart contract development kit for AssemblyScript on the NEAR platform
you can see how RNG is used in this example
https://github.com/Learn-NEAR/NCD.L1.sample--lottery/blob/ff6cddaa8cac4d8fe29dd1a19b38a6e3c7045363/src/lottery/assembly/lottery.ts#L12-L13
class Lottery {
private chance: f64 = 0.20
play(): bool {
const rng = new RNG<u32>(1, u32.MAX_VALUE);
const roll = rng.next();
logging.log("roll: " + roll.toString());
return roll <= <u32>(<f64>u32.MAX_VALUE * this.chance);
}
}
and how the constructor is implemented here:
https://github.com/near/near-sdk-as/blob/f3707a1672d6da6f6d6a75cd645f8cbdacdaf495/sdk-core/assembly/math.ts#L152
the first argument is the length of the buffer holding random numbers generated from the seed. you can use the next() method to get more numbers from this buffer with each call
export class RNG<T> {
constructor(len: u32, public max: u32 = 10_000) {
let real_len = len * sizeof<T>();
this.buffer = math.randomBuffer(real_len);
this._last = this.get(0);
}
next(): T {}
}
If you remove the item from oldList once picked, it would be imposible to picked it again.
Another aproach is to shuffle your oldList and then pick the first two items.
I might have been found a bug in ColdFusion 2016.
I have two functions. The first one has a loop which iterates from 1 to n and pushes the return value of the second function which is also an array into an array. I noticed that;
index value is 1,
calling function and pushing the value into the array,
and index value is the end value of the loop.
Is this a bug?
<cfscript>
public array function fnc1(required array p1, required array p2, required numeric pSize, required numeric qSize, required numeric dSize){
iterationNum = pSize/2;
point = randRange(1, qSize-1);
for(i = 1; i <= iterationNum; i++){
writeOutput(i); // prints: 1
pop[i] = fnc2(p1[i], p2[i], point);
writeOutput(i); // prints: iterationNum value
writeDump(var = pop[i], label = "pop-"&i);
}
writeDump(var = pop, label="pop");
}
public array function fnc2(required array p1, required array p2, required numeric point){
n = arrayLen(p1);
concatArr = arrayNew(1);
for(i = 1; i <= point; i++){
concatArr[i] = p1[i];
}
for(i = point + 1; i <= n; i++){
concatArr[i] = p2[i];
}
writeDump(var=concatArr, label="Concated Array");
return concatArr;
}
</cfscript>
The default scope of a variable inside of a cfc is not function only. But rather it is cfc wide. This is often problematic.
Similarly, the default scope of a variable outside of a cfc is request wide. This is often useful.
Two approaches
There are two approaches to limit the scope of a variable inside of a cfc. One is to use the keyword var, the other is the use local.
It is a long story as to how they are different. The sample solution below uses var throughout. If you want to know more about var vs local., click here: Scoping: Local vs Var
<cfscript>
public array function fnc1(required array p1, required array p2, required numeric pSize, required numeric qSize, required numeric dSize){
var iterationNum = pSize/2;
var point = randRange(1, qSize-1);
for(var i = 1; i <= iterationNum; i++){
writeOutput(i); // prints: 1
pop[i] = fnc2(p1[i], p2[i], point);
writeOutput(i); // prints: iterationNum value
writeDump(var = pop[i], label = "pop-"&i);
}
writeDump(var = pop, label="pop");
}
public array function fnc2(required array p1, required array p2, required numeric point){
var n = arrayLen(p1);
var concatArr = arrayNew(1);
for(var i = 1; i <= point; i++){
concatArr[i] = p1[i];
}
for(var ii = point + 1; ii <= n; ii++){
concatArr[ii] = p2[ii];
}
writeDump(var=concatArr, label="Concated Array");
return concatArr;
}
</cfscript>
I keep getting these errors when I run my program, can anyone spot the mistake? I am not experienced with using recursion and I might have messed up base case. My testing consists of two numbers of the same length, and my goal is to multiply two Big numbers without using the built in class. The method add just takes in two strings which are numbers and adds them, I checked and it works no matter how big the numbers are.
Error NumberFormatException: For input string: ""
Integer.parseInt(Integer.java:592)
public static String mu (String value1, String value2){
int length1 = value1.length();
int length2 = value2.length();
//If one value has more digits than the other, add zeroes to the front...
int temp1;
int temp2;
int multiply;
if (length1==1 || length2 ==1){
temp1 = Integer.parseInt(value1);
temp2 = Integer.parseInt(value2);
multiply = temp1*temp2;
return multiply +"" ;
}else if (length1 ==0 || length2 ==0){
return "";
}
int firstHalf = length1/2;
int secondHalf = length1 - firstHalf;
String value1First = value1.substring(0, firstHalf);
String value1Second = value1.substring(firstHalf, secondHalf);
String value2First = value2.substring(0, firstHalf);
String value2Second = value2.substring(firstHalf, secondHalf);
String ac = mu (value1First, value2First);
String ad = mu (value1First, value2Second);
String bc = mu(value1Second, value2First);
String bd = mu(value1Second, value2Second);
String zeroesToAdd= null;
String zeroesToAdd2 = null;
for (int i=0; i<length1; i++){
zeroesToAdd = "0"+ zeroesToAdd;
}
for (int i=0; i<length1/2; i++){
zeroesToAdd2 = "0"+ zeroesToAdd2;
}
String firstPart = ac + zeroesToAdd;
String secondPart = (add(ad,bc))+zeroesToAdd2;
String thirdPart = bd;
String add1 = add(firstPart, secondPart);
String add2;
return add(add1, thirdPart);
}
Error NumberFormatException: For input string: ""
Integer.parseInt(Integer.java:592)
is caused by the code
Integer.parseInt(value1) or
Integer.parseInt(value2)
You might want to try add more cases for combination of str lengths (1,1) (1,0) (0,1) (0,0). Following code might help!
if (length1==1 && length2 ==1){
temp1 = Integer.parseInt(value1);
temp2 = Integer.parseInt(value2);
multiply = temp1*temp2;
return multiply +"" ;
}else if (length1 ==0 && length2 ==0){
return "";
}
else if (length1 ==0 && length2 ==1){
return value2;
}
else if (length1 ==1 && length2 ==0){
return value1;
}
Hope it helps!
I am using a 2 linked list to represent 2 very long integers, each digit occupy one node. I need to compute for their gcf fast but my current algorithm computes for a very long time. Please help me improve it/or if you can suggest other faster algorithms for linked list.
here's my current code:
int findGCD(number **larger, number **small, number **gcdtop){
number *a = *larger, *b = *small, *aptr, *bptr;
printlist(larger);
printlist(small);
int equal = checkEqual(a, b); //traverse through linked list a & b and compare if equal, returns 1 if true
int large=0, borrow=0, adata=0, bdata=0, i=0;
while(equal!=1){
equal = checkEqual(a, b);
if(equal==1) break;
flip(&a); //Flips the linked list
flip(&b);
large = whatGreater(&a, &b); //Checks which linkedlist is greater
flip(&a); //Flip it back
flip(&b);
borrow=0;
//Do repeated subtraction (Euclid's algorithm)
if(large==1){
aptr = a;
bptr = b;
while(a && b){
adata = a->data;
bdata = b->data;
adata = adata - borrow;
if(adata>=bdata){
a->data = (adata-bdata);
borrow=0;
}
else if(adata<bdata){
adata = adata+10;
a->data = (adata-bdata);
borrow = 1;
}
a = a->next;
b = b->next;
}
a = aptr;
b = bptr;
}
else if(large==0){
aptr = a;
bptr = b;
while(a && b){
adata = a->data;
bdata = b->data;
bdata = bdata - borrow;
if(bdata>=adata){
b->data = (bdata-adata);
borrow=0;
}
else if(bdata<adata){
bdata = bdata+10;
b->data = (bdata-adata);
borrow = 1;
}
a = a->next;
b = b->next;
}
a = aptr;
b = bptr;
}
}
I believe doing this division/modulo would be faster but I cannot implement it in linked list.
Here's a sample input: 15424832369192002264032565635067237193339888184999832384884463019917546384661904, 65227
Thank you in advance.
I have a List where I would like to add an internal counter when several items have the same name.
var myList = new List<string>();
myList.Add("a");
myList.Add("b");
myList.Add("b");
myList.Add("c");
And I want the result to be
a01
b01
b02
c01
after some fancy LINQ stuff.
Any great ideas out there?
Not saying that's nice, but it's a (mostly) Linq solution:
var indexed = from index in myList.Aggregate(
new
{
Counters = new Dictionary<string, int>(),
Items = new List<string>()
},
(acc, cur) =>
{
if (!acc.Counters.ContainsKey(cur))
acc.Counters.Add(cur, 0);
acc.Counters[cur] = acc.Counters[cur] + 1;
acc.Items.Add(cur + acc.Counters[cur]);
return acc;
}).Items
select index;
The accumulation part is pretty ugly, but it does the job and all inside a Linq computation.
EDIT
If the initial list is already sorted, this expression is cleaner (but might be inefficient, you'd have to see how many items you have in your list):
var indexed = from index in myList.Aggregate(
new
{
Counter = 0,
Key = (string)null,
Items = Enumerable.Empty<string>()
},
(acc, cur) =>
{
var counter = acc.Key != cur ? 1 : acc.Counter+1;
return new
{
Counter = counter,
Key = cur,
Items = acc.Items.Concat(
Enumerable.Repeat(cur + counter, 1))
};
}).Items
select index;
If you want to preserve the order, there's no amazingly nice way to do this in OOTB LINQ, but you could knock something up like
public static IEnumerable<TResult> SelectWithUniquifier<TSource, TResult>(
this IEnumerable<TSource> source, Func<TSource, int, TResult> uniquifier)
{
Dictionary<TSource, int> counter = new Dictionary<TSource, int>();
foreach(TSource s in source)
{
int thisIndex = counter.ContainsKey(s) ? counter[s] : 0;
counter[s] = thisIndex + 1;
yield return uniquifier(s, thisIndex);
}
}
just with a better name.
For your example you'd have
var result = myList.SelectWithUniquifier((s, i) => s + (i+1).ToString("00"));
as the index you get is zero-based.
See other answers for some fancy (and pretty confusing) LINQ solutions. If you don't necessarily need to use LINQ:
var myList = new List<string> { "a", "b", "c", "b" };
var counter = new ConcurrentDictionary<string, int>();
for (int i = 0; i < myList.Count; i++)
{
var currVal = myList[i];
counter.AddOrUpdate(currVal, 1, (value, count) => count + 1);
myList[i] = currVal + counter[currVal].ToString("00");
}
ConcurrentDictionary is not needed, you can do the "add or update" thing manually, depending on how you value speed vs code clarity. Either way, in my opinion this is a much more readable and maintainable way to do what you want to do. Don't be scared of ye olde for loop. :)
Of course this could be done as an extension method, or a static method on some utility class etc.
Another simpler way:
var result = myList.GroupBy(x => x)
.SelectMany(g => g.Select((x, i) => x + (i + 1).ToString("00")));
var res =
myList
.GroupBy(item => item)
.Select(item => String.Format("{0}{1}", item.Key, item.Count()));