Predicate being ignored in core data fetch request - core-data

Can anyone tell me why the questionFetch predicate below is being ignored and the questionResults.count being returned is the number of rows in the entire data set? There are only 2 rows in the data set with a questionType equal to 0, which should be the only two rows returned. Instead all 88 rows of data are being returned.
let questionFetch: NSFetchRequest<Question> = Question.fetchRequest()
questionFetch.predicate = NSPredicate(format: "%K == %iā€,
#keyPath(Question.questionType), currentQuestionType)
let questionResults = try
modelController.coreDataStack.managedContext.fetch(questionFetch)
print("questionResults.count: ", questionResults.count)
Note that I have also tried with the hard-coded value in the comparison to make sure that the problem is not due to an incorrect value in the currentQuestionType variable.
questionFetch.predicate = NSPredicate(format: "%K == 0ā€,
#keyPath(Question.questionType))
Yet the choiceFetch predicate below, with nearly identical logic, is limiting the results appropriately.
let choiceFetch: NSFetchRequest<Choice> = Choice.fetchRequest()
choiceFetch.predicate = NSPredicate(format: "%K == %i",
#keyPath(Choice.questionID), currentQuestionID)
let choiceResults = try managedContext.fetch(choiceFetch)
print("choiceResults.count: ", choiceResults.count)
Any ideas would be appreciated.

Related

Python adding column with condition not working as expected

I am trying to add a column based on a condition like
for i in range(len(data) - 1):
a = data.loc[i, 'column1']
b = data.loc[i+1, 'column1']
if a == b:
data['column2'] = 1
else:
data['column2'] = 0
This shows no error and the new column has been created, however the logic does not work, the new column is filled with 0 regardless of the logic. I have checked if a == b by printing the values for a and b with a == b and the result is as I expected. I am not sure why that is?
Note that the reason why I am using if statements is because my logic involves if and, else if
Inside the if statement, it should be data.loc[i,'column2'] this way it will right in the value at that location

comparing int value in list throws index out of range Error

I'm struggling to grasp the problem here. I already tried everything but the issue persist.
Basically I have a list of random numbers and when I try to compare the vaalues inside loop it throws "IndexError: list index out of range"
I even tried with range(len(who) and len(who) . Same thing. When put 0 instead "currentskill" which is int variable it works. What I don't understand is why comparing both values throws this Error. It just doesn't make sence...
Am I not comparing a value but the index itself ???
EDIT: I even tried with print(i) / print(who[i] to see if everything is clean and where it stops, and I'm definitelly not going outside of index
who = [2, 0, 1]
currentskill = 1
for i in who:
if who[i] == currentskill: # IndexError: list index out of range
who.pop(i)
The problem is once you start popping out elements list size varies
For eg take a list of size 6
But you iterate over all indices up to len(l)-1 = 6-1 = 5 and the index 5 does not exist in the list after removing elements in a previous iteration.
solution for this problem,
l = [x for x in l if x]
Here x is a condition you want to implement on the element of the list which you are iterating.
As stated by #Hemesh
The problem is once you start popping out elements list size varies
Problem solved. I'm just popping the element outside the loop now and it works:
def deleteskill(who, currentskill):
temp = 0
for i in range(len(who)):
if who[i] == currentskill:
temp = i
who.pop(temp)
There are two problems in your code:
mixing up the values and indexes, as pointed out by another answer; and
modifying the list while iterating over it
The solution depends on whether you want to remove just one item, or potentially multiple.
For removing just one item:
for idx, i in enumerate(who)::
if i == currentskill:
who.pop(idx)
break
For removing multiple items:
to_remove = []
for idx, i in enumerate(who)::
if i == currentskill:
to_remove.append[idx]
for idx in reversed(to_remove):
who.pop(idx)
Depending on the situation, it may be easier to create a new list instead:
who = [i for i in who if i != currentskill]
Your logic is wrong. To get the index as well as the value, use the built-in function enumerate:
idx_to_remove = []
for idx, i in enumerate(who)::
if i == currentskill:
idx_to_remove.append[idx]
for idx in reversed(idx_to_remove):
who.pop(idx)
Edited after suggestion from #sabik

AQL: How to get back the path that all edges must have an property(array) and that array must have at least one certain value

Suppose I have an graph like this:
A---edge1---B property P [P1,P2]
B---edge2---C property P [P2,P3]
C---edge3---D property P [P2,P3]
B---edge4---D property P [P1,P3]
And each edge have an property P which is an array of string [P1,P2,P3]. Each edge has their own value of P
Now I would like to return all vertexes that:
For Each vertex, check if exist a path where each edges, all of them must have at least P2 in property
Depth smaller or equals then 2
**
For entity in entities
For v,e,p in Collection in 0..2 ANY entity
Filter //What should I do here? I tried p.edges[*].P[*] ANY =="P2"
Collect v._key into groups
return {key:v._key,group:groups} //Get the vertex that satisfy the condition
**
p.edges[*].P[*] is an array of arrays. To get ANY == to compare array to individual element would require a flattened array, but then it cannot be determined whether each array has "P2".
One of the following conditions should work however:
FILTER p.edges[* RETURN "P2" IN CURRENT.P] ALL == true
FILTER (FOR arr IN p.edges[*].P RETURN "P2" IN arr) ALL == true
FILTER LENGTH(p.edges[* FILTER "P2" IN CURRENT.P]) == LENGTH(p.edges)

Safe range operator in Groovy?

Is there a safe range operator for Groovy?
For instance if I have,
[1,2,3][0..10]
Groovy will throw a java.lang.IndexOutOfBoundsException:
Is there a index safe way to access this range? Or do I always have to check the collection size prior to running a range?
You can use take(n), which allows you to take up to a specific number of items, without error if there's too few in the collection:
def input = [1,2,3]
def result = input.take(10)
assert result == [1,2,3]
input = [1,2,3,4,5]
result = input.take(4)
assert result == [1,2,3,4]
If you need to start at an offset, you can use drop(n), which does not modify the original collection:
def input = [1,2,3,4,5]
def result = input.drop(2).take(2)
assert result == [3,4]
These are both safe against the size of the collection. If the list is too small in the last example, you may only have one or zero items in the collection.

Sorting Excel rows alphabetically in F# (Office.Interop)

I am using the Excel interop in Visual Studio 2010 to try to sort all of these rows of data alphabetically. Some are already in alphabetical order.
Accountancy Graduate, Trainees Banking, Insurance, Finance
Accountancy Graduate, Trainees Customer Services
Accountancy Graduate, Trainees Education
Accountancy Graduate, Trainees Health, Nursing
Accountancy Graduate, Trainees Legal
Accountancy Graduate, Trainees Management Consultancy
Accountancy Graduate, Trainees Media, New Media, Creative
Accountancy Graduate, Trainees Oil, Gas, Alternative Energy
Accountancy Graduate, Trainees Public Sector & Services
Accountancy Graduate, Trainees Recruitment Sales
Accountancy Graduate, Trainees Secretarial, PAs, Administration
Accountancy Graduate, Trainees Telecommunications
Accountancy Graduate, Trainees Transport, Logistics
The current version of my code is as follows (I'm getting my code to work in interactive before putting it into an fs file).
#r "office.dll"
#r "Microsoft.Office.Interop.Excel.dll"
open System;;
open System.IO;;
open Microsoft.Office.Interop.Excel;;
let app = new ApplicationClass(Visible = true)
let inputBook = app.Workbooks.Open #"C:\Users\simon.hayward\Dropbox\F# Scripts\TotalJobsSort\SortData.xlsx" //work
//let inputBook = app.Workbooks.Open #"C:\Users\Simon Hayward\Dropbox\F# Scripts\TotalJobsSort\SortData.xlsx" //home
let outputBook = app.Workbooks.Add()
let inSheet = inputBook.Worksheets.[1] :?> _Worksheet
let outSheet = outputBook.Worksheets.[1] :?> _Worksheet
let rows = inSheet.UsedRange.Rows.Count;;
let toSeq (range : Range) =
seq {
for r in 1 .. range.Rows.Count do
for c in 1 .. range.Columns.Count do
let cell = range.Item(r, c) :?> Range
yield cell
}
for i in 1 .. rows do
let mutable row = inSheet.Cells.Rows.[i] :?> Range
row |> toSeq |> Seq.map (fun x -> x.Value2.ToString()) |> Seq.sort |>
(outSheet.Cells.Rows.[i] :?> Range).Value2 <- row.Value2;;
app.Quit();;
But there is a problem with types. The final line before the quit command
(outSheet.Cells.Rows.[i] :?> Range).Value2 <- row.Value2;;
Is red underlined by intellisense and the error I get is
"This expression is expected to have type seq -> 'a but here has type unit".
I get what VS is trying to tell me, but I have made several attempts to fix this now and i can't seem to get around the type issue.
Can anyone please advise how I can get the pipeline to the correct type so that the output will write to my output sheet?
EDIT 1: This is the full error message that I get with the sorted variable commented out as follows
let sorted = row |> toSeq //|> Seq.map (fun x -> x.Value2.ToString()) |> Seq.sort
The error message is:-
System.Runtime.InteropServices.COMException (0x800A03EC): Exception from HRESULT: 0x800A03EC
at System.RuntimeType.ForwardCallToInvokeMember(String memberName, BindingFlags flags, Object target, Int32[] aWrapperTypes, MessageData& msgData)
at Microsoft.Office.Interop.Excel.Range.get_Item(Object RowIndex, Object ColumnIndex)
at FSI_0122.toSeq#34-47.Invoke(Int32 c) in C:\Users\Simon Hayward\Dropbox\F# Scripts\TotalJobsSort\sortExcelScript.fsx:line 36
at Microsoft.FSharp.Collections.IEnumerator.map#109.DoMoveNext(b& )
at Microsoft.FSharp.Collections.IEnumerator.MapEnumerator1.System-Collections-IEnumerator-MoveNext()
at Microsoft.FSharp.Core.CompilerServices.RuntimeHelpers.takeOuter#651[T,TResult](ConcatEnumerator2 x, Unit unitVar0)
at Microsoft.FSharp.Core.CompilerServices.RuntimeHelpers.takeInner#644[T,TResult](ConcatEnumerator2 x, Unit unitVar0)
at <StartupCode$FSharp-Core>.$Seq.MoveNextImpl#751.GenerateNext(IEnumerable1& next)
at Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase1.MoveNextImpl()
at Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase1.System-Collections-IEnumerator-MoveNext()
at Microsoft.FSharp.Collections.SeqModule.ToArray[T](IEnumerable1 source)
at Microsoft.FSharp.Collections.ArrayModule.OfSeq[T](IEnumerable1 source)
at .$FSI_0122.main#() in C:\Users\Simon Hayward\Dropbox\F# Scripts\TotalJobsSort\sortExcelScript.fsx:line 42
Stopped due to error
EDIT 2: Could this problem be due to the toSeq function being designed to turn a whole sheet into a sequence? Where I apply it I only want it to apply to one row.
I have tried limiting the r variable in toSeq to 1, but this didn't help.
Does the fact that my actual data is a jagged array matter? It does not always have 3 entries in each row, it varies between 1 and 4.
EDIT 3:
Here is the current iteration of my code, based on Tomas' suggestions
#r "office.dll"
#r "Microsoft.Office.Interop.Excel.dll"
open System;;
open System.IO;;
open Microsoft.Office.Interop.Excel;;
let app = new ApplicationClass(Visible = true);;
let inputBook = app.Workbooks.Open #"SortData.xlsx" //workbook
let outputBook = app.Workbooks.Add();;
let inSheet = inputBook.Worksheets.[1] :?> _Worksheet
let outSheet = outputBook.Worksheets.[1] :?> _Worksheet
let rows = inSheet.UsedRange.Rows.Count;;
let columns = inSheet.UsedRange.Columns.Count;;
// Get the row count and calculate the name of the last cell e.g. "A13"
let rangeEnd = sprintf "A%d" columns
// Get values in the range A1:A13 as 2D object array of size 13x1
let values = inSheet.Range("A1", rangeEnd).Value2 :?> obj[,]
// Read values from the first (and only) column into 1D string array
let data = [| for i in 1 .. columns -> values.[1, i] :?> string |]
// Sort the array and get a new sorted 1D array
let sorted1D = data |> Array.sort
// Turn the 1D array into 2D array (13x1), so that we can write it back
let sorted2D = Array2D.init 1 columns (fun i _ -> data.[i])
// Write the data to the output sheet in Excel
outSheet.Range("A1", rangeEnd).Value2 <- sorted2D
But because the actual data has a variable number of entries in each row I am getting the standard range exception error (this is an improvement on the HRESULT exception errors of the last few days at least).
So I need to define columns for each individual row, or just bind the length of the row to a variable in the for loop. (I would guess).
It looks like you have an additional |> operator at the end of the line with Seq.sort - this means that the list is sorted and then, the compiler tries to pass it to the expression that performs the assignment (which does not take any parameter and has a type unit).
Something like this should compile (though there may be some other runtime issues):
for i in 1 .. rows do
let row = inSheet.Cells.Rows.[i] :?> Range
let sorted = row |> toSeq |> Seq.map (fun x -> x.Value2.ToString()) |> Seq.sort
(outSheet.Cells.Rows.[i] :?> Range).Value2 <- Array.ofSeq sorted
Note that you do not need to mark row as mutable, because the code creates a copy (and - in my version - assigns it to a new variable sorted).
I also use Array.ofSeq to convert the sorted sequence to an array, because I think the Excel interop works better with arrays.
When setting the Value2 property on a range, the size of the range should be the same as the size of the array that you're assigning to it. Also, depending on the range you want to set, you might need a 2D array.
EDIT Regarding runtime errors, I'm not entirely sure what is wrong with your code, but here is how I would do the sorting (assuming you have just one column with string values and you want to sort the rows):
// Get the row count and calculate the name of the last cell e.g. "A13"
let rows = inSheet.UsedRange.Rows.Count
let rangeEnd = sprintf "A%d" rows
// Get values in the range A1:A13 as 2D object array of size 13x1
let values = inSheet.Range("A1", rangeEnd).Value2 :?> obj[,]
// Read values from the first (and only) column into 1D string array
let data = [| for i in 1 .. rows -> values.[i, 1] :?> string |]
// Sort the array and get a new sorted 1D array
let sorted1D = data |> Array.sort
// Turn the 1D array into 2D array (13x1), so that we can write it back
let sorted2D = Array2D.init rows 1 (fun i _ -> data.[i])
// Write the data to the output sheet in Excel
outSheet.Range("A1", rangeEnd).Value2 <- sorted

Resources