Need good explanation of MPMediaQuery results for collections and items - swift3

I need some help in understanding MPMediaQuery and how to access the results so that I can use the query with setQueue(with:).
Here's an example of why I am confused.
In my library I have an artist with 3 albums.
My goal is a query for those 3 albums, in order with each track in order:
Album A
track 1
track 2
track 3
Album 2
track 1
track 2
track 3
Album 3
track 1
track 2
track 3
When I use this query, the Albums/songs are not in order as expected.
They almost appear shuffled even though shuffle is NOT on.
var qryArtists = MPMediaQuery()
qryArtists = MPMediaQuery.artists()
qryArtists.groupingType = MPMediaGrouping.albumArtist
let currLoc = qryArtists.collectionSections![indexPath.section].range.location
myMP.setQueue(with: qryArtists.collections![indexPath.row + currLoc])
for junk in qryArtists.collections![indexPath.row + currLoc].items{
print(" collections title \(junk.albumTitle!) track \(junk.albumTrackNumber) song \(junk.title!)")
}
I get these results:
collections title Cosmic Thing track 8 song Channel Z
collections title Cosmic Thing track 1 song Cosmic Thing
collections title Wild Planet track 6 song Devil In My Car
collections title Wild Planet track 2 song Dirty Back Road
collections title Wild Planet track 4 song Give Me Back My Man
collections title Cosmic Thing track 5 song June Bug
collections title Wild Planet track 1 song Party Out Of Bounds
collections title Wild Planet track 5 song Private Idaho
collections title Wild Planet track 7 song Quiche Lorraine
collections title Cosmic Thing track 6 song Roam
collections title The B-52's track 15 song Rock Lobster
collections title Wild Planet track 3 song Runnin' Around
collections title Wild Planet track 8 song Strobe Light
collections title Cosmic Thing track 9 song Topaz
collections title Wild Planet track 9 song 53 Miles West Of Venus
Notice the Albums/Songs are not in proper order
However, if I use this print statement instead I get expected results:
for junk in newQry.items!{
print("items title \(junk.albumTitle!) track \(junk.albumTrackNumber) song \(junk.title!)")
}
Results:
items title The B-52's track 15 song Rock Lobster
items title Cosmic Thing track 1 song Cosmic Thing
items title Cosmic Thing track 5 song June Bug
items title Cosmic Thing track 6 song Roam
items title Cosmic Thing track 8 song Channel Z
items title Cosmic Thing track 9 song Topaz
items title Wild Planet track 1 song Party Out Of Bounds
items title Wild Planet track 2 song Dirty Back Road
items title Wild Planet track 3 song Runnin' Around
items title Wild Planet track 4 song Give Me Back My Man
items title Wild Planet track 5 song Private Idaho
items title Wild Planet track 6 song Devil In My Car
items title Wild Planet track 7 song Quiche Lorraine
items title Wild Planet track 8 song Strobe Light
items title Wild Planet track 9 song 53 Miles West Of Venus
Also, another very strange effect: If I set the MusicPlayer query:
myMP.setQueue(with: newQry)
and then issue the SAME 'items' print statement, the results are now mixed in the exact same way as the 'collections' version!
Why would setting the queue change the way the query behaves?
Since I can't setQueue with newQry.items, how can I build a queue to get the Albums and Songs in expected order?

OK, I solved this myself with a lot more research.
The trick here is to use the ITEMS which are sorted correctly, and build a new Collection to use as the queue.
All it takes is that addition of a single line of code:
let collection = MPMediaItemCollection(items: newQry.items!)
and then a change to the setQueue function:
myMP.setQueue(with: collection)
Here's the final working code block - compare to my original post OP above:
let newQry = MPMediaQuery.albums()
newQry.addFilterPredicate(
MPMediaPropertyPredicate(
value: artistArray[indexPath.row + currLoc],
forProperty: MPMediaItemPropertyAlbumArtist,
comparisonType: .equalTo
)
)
//build a new collection with the sorted items then load the collection!
let collection = MPMediaItemCollection(items: newQry.items!)
myMP.stop()
myMP.setQueue(with: collection)
myMP.play()

Related

Iterating through a list of lists with transitive property

I'm looking for a proper way to transform the data:
similarities = [["Parasite", "1917"],
["Parasite", "Jojo Rabbit"],
["Joker", "Ford v Ferrari"]]
In each sublist there are films that are similar, I need to be able to iterate through it somehow, to count how many similar films each one has. Similar movies have transitive property: if movie 1 is similar to movie 2 and movie 2 is similar to movie 3 -> movie 1 is similar to movie 3 and vice versa.
The outcome is like this:
Joker - 1 (Ford v Ferrari)
1917 - 2 (Parasite, Jojo Rabbit)
Parasite - 2 (1917, Jojo Rabbit)
Jojo Rabbit - 2 (Parasite, 1917)
Ford v Ferrari - 1 (Joker)
I thought of a dict or a graph traversal, but nothing seems to work so far

Pandas: Create New Dataframe that Counts Number of Times Keywords / Phrases From List Occur in One Column

I have the following word list:
list = ['clogged drain', 'right wing', 'horse', 'bird', 'collision light']
I have the following data frame (notice spacing can be weird):
ID TEXT
1 you have clogged drain
2 the dog has a right wing clogged drain
3 the bird flew into collision light
4 the horse is here to horse around
5 bird bird bird
I want to create a table that shows keywords and frequency counts of how often the keywords occurred in TEXT field. However, if a keyword appears more than once in the same row within the TEXT column, it is only counted once.
Desired output:
keywords count
clogged drain 2
right wing 1
horse 1
bird 2
collision light 1
I have searched all over stackoverflow but couldn't find my specific case.
I would start by reformatting the TEXT column to get rid of your funny spacing, using str.split() and str.join(). Then, use str.contains for each of your keywords, and get the sum of the boolean values that are outputted (It will return True if your keyword is found):
# Reformat text, splitting wherever you have one or more spaces
df['formatted_text'] = df.TEXT.str.split('\s+').str.join(' ')
# create your output dataframe
df2 = pd.DataFrame(my_list, columns=['keywords'])
# Count occurences:
df2['count'] = df2['keywords'].apply(lambda x: df.formatted_text.str.contains(x).sum())
The result:
>>> df2
keywords count
0 clogged drain 2
1 right wing 1
2 horse 1
3 bird 2
4 collision light 1
Just to note, I changed the variable name of your list to my_list, so as not to mask the built in python data type
You can using extractall
df.TEXT.str.extractall(r'({})'.format('|'.join(list)))[0].str.get_dummies().sum(level=0).gt(0).astype(int).sum()
Out[225]:
bird 2
clogged drain 2
collision light 1
horse 1
right wing 1
dtype: int64

display a parent-child-child with django

I'm new to Django and get easily lost.
I have this app that have items. They are set as a list with parent-child relations.
Later I want to display tasks attached to items. But for now. I can't even figure out how to display the parent-childs.
This is my simplt model
class Item(models.Model):
item_title = models.Charfield()
item_parent = models.ForeignKey('self')
I want to display them as:
Item 1
- item 2
- item 3
-- item 4
-- item 5
Item 6
- item 7
-- item 8
--- item 9
I have tried with making a view that take Item.objects.all().order_by('item_parent')
And the template with a FOR - IN. But I don't know how to seperate to show first parent then child, and another child is that exist.
I just manage to list everthing in order by the item_parent. Which is not the same.
Appreciate some expert help to a beginner like me.
If performance is not an issue then a solution based on MaximeK's answer is the simplest. The performance is not great as you are recursively querying the database. For a very small amount of items this is OK.
A more efficient way that also can support an indefinite depth of children is to fetch all the items at once and then create a tree that you can then traverse to print the items in order. It is more code to write but it might be educational if not directly helpful with your problem.
First step: we generate a tree for each item that does not have a root (stored in roots). Side note: We can think of these trees as one big tree starting at a single root node that has all the items with no parents as children, but for simplicity we don't do that.
references = {}
roots = []
items = Item.objects.all()
for item in items:
# get or make a new node
if item.pk in references:
n = references[item.pk]
n.item = item
else:
n = Node(children=[], item=item)
references[item.pk] = n
if item.item_parent is None:
# if item is root (no parent)
roots.append(n)
else:
# if item has a parent
if item.item_parent_id in references:
# item parent already seen
parent_n = references[item.item_parent_id]
else:
# item not seen yet
parent_n = Node(children=[], item=None)
parent_n.children.append(n)
Second step: we traverse the tree depth-first
def dfs(root, level=0):
print("-"*level, root.item.item_title)
for node in root.children:
dfs(node, level+1)
for root in roots:
dfs(root)
This is just printing the item_title with - in front to denote the indentation level. I generated some random items and the output looks like this:
python mouse cat
- mouse monitor car
-- blue car cat
green machine computer
- monitor green yellow
yellow pen blue
- mouse cat yellow
yellow blue green
- cat monitor python
-- blue yellow python
-- machine green cat
--- monitor blue python
-- machine computer mouse
-- machine car blue
car pen yellow
I don't know how to do this in Django templates, but we can generate HTML that looks like this:
<ul>
<li>pen monitor cat
<ul>
<li>computer mouse machine</li>
<li>yellow python car
<ul>
<li>monitor python pen</li>
<li>mouse blue green</li>
<li>python blue cat</li>
</ul>
</li>
</ul>
</li>
<li>mouse computer cat</li>
<li>computer python car
<ul>
<li>pen green python
<ul>
<li>mouse computer machine</li>
</ul>
</li>
<li>machine yellow mouse</li>
</ul>
</li>
<li>yellow python monitor</li>
<li>car cat pen
<ul>
<li>pen machine blue
<ul>
<li>mouse computer machine</li>
</ul>
</li>
</ul>
</li>
</ul>
Depth-first traversal that generates the above HTML. I wrote it as a class to avoid global variables.
class TreeHtmlRender:
def __init__(self, roots):
self.roots = roots
def traverse(self):
self.html_result = "<ul>"
for root in self.roots:
self.dfs(root, 0)
self.html_result += "</ul>"
return self.html_result
def dfs(self, root, level=0):
self.html_result += ("<li>%s" % root.item.item_title)
if len(root.children) > 0:
self.html_result += "<ul>"
for node in root.children:
self.dfs(node, level+1)
self.html_result += "</ul>"
self.html_result += "</li>"
r = TreeHtmlRender(roots)
print(r.traverse())
To render on a webpage you can simply send the HTML to your template via a context and use the safe flag ({{ items_tree | html }}). You can pack all I said in this answer into a neat template tag that will render trees if you need or want to.
Note: A clear limitation of this approach is that it will not function properly if not all items are selected. If you select a subset of all your items and if it happens that you select child nodes and omit their parents, the child nodes will never be displayed.
You need to use :
item_parent__self_set
Its mean for each item_parent you have the childs list (_set if for query_set)
When you define a ForeignKey, you automatically get a reverse relation.
You can do something more simple :
class Item(models.Model):
item_title = models.Charfield()
item_parent = models.ForeignKey('self', blank=True, null=True, related_name='children')
And you retrieve :
for item in Item.objects.filter(item_parent__isnull=True):
print item.item_title
for child in item.children.all():
print child.item_title

Opencart, I want to see the category name in my product search

Small example, I have 3 categories: small tea mug, normal tea mug, and large tea mug.
The all have the same products: white mug, blue mug, and green mug. The pictures are squares in the same color. So when I search for blue I get 3 hits for blue, but can't see if it is for the small, normal or large. How can I add the category for these products?
Thanks!

Filter items with Django Query

I'm encountering this problem and would like to seek your help.
The context:
I'm having a bag of balls, each of which has an age (red and blue) and color attributes.
What I want is to get the top 10 "youngest" balls and there are at most 3 blue balls (this means if there are more than 3 blue balls in the list of 10 youngest balls, then replace the "redudant" oldest blue balls with the youngest red balls)
To get top 10:
sel_balls = Ball.objects.all().sort('age')[:10]
Now, to also satisfy the conditions "at most 3 blue balls", I need to process further:
Iterate through sel_balls and count the number of blue balls (= B)
If B <= 3: do nothing
Else: get additional B - 3 red balls to replace the oldest (B - 3) blue balls (and these red balls must not have appeared in the original 10 balls already taken out). I figure I can do this by getting the oldest age value among the list of red balls and do another query like:
add_reds = Ball.objects.filter(age >= oldest_sel_age)[: B - 3]
My question is:
Is there any way that I can satisfy the constraints in only one query?
If I have to do 2 queries, is there any faster ways than the one method I mentioned above?
Thanks all.
Use Q for complex queries to the database: https://docs.djangoproject.com/en/dev/topics/db/queries/#complex-lookups-with-q-objects
You should use annotate to do it.
See documentation.
.filter() before .annotate() gives 'WHERE'
.filter() after .annotate() gives 'HAVING' (this is what you need)