Can Repeater Model execute JAVASCRIPT? - javascript

I have an XmlListModel in QML
XmlListModel {
id: model
source: "qrc:/Config/myConfig.xml"
query: "/levels/level"
XmlRole { name: "levName"; query: "#levName/string()" }
XmlRole { name: "from"; query: "from/number()" }
XmlRole { name: "to"; query: "to/number()" }
}
that reads this XML file
<levels parId = "3">
<level levelName = "level1">
<from>0</from>
<to>1</to
</level>
<level levelName = "level2">
<from>1</from>
<to>2</to>
</level>
</levels>
I also have a text element:
Text {
id: myText
x: 0; y:0
text: ""
}
I need to iterate through the XmlListModel in order to assign to myText.text the right level on the basis of what I found in myList.get(3).value, where myList is a ListModel.
Example:
if myList.get(3).value is between 0 (included) and 1 (excluded) I have to set myText.text = "level1", if it is between 1 (included) and 2 (excluded) I have to set myText.text = "level2", and so on...
Any suggestion?

Unfortunately you can't query your XmlListModel in O(1) like give me the value, where x is between role from and role to.
Good for you, you have an ordered list, so you can perform a binary search on your XmlListModel. The algorithm basically goes like this:
You first check whether your search value is by coincidence the one in the middle. If it is smaller, you search in the middle of the lower half, if it is larger, you search in the upper half... and so on.
With this you can find your value in O(log n) where n is the number of entries in your XmlListModel.
https://en.wikipedia.org/wiki/Binary_search_algorithm
If you have this implemented, to work on your model - either in JavaScript or in C++ or Python... you can have it like this:
Text {
text: binarySearch(model, myList.get(3).value).levName
}
When you implement this algorithm, make sure to deal with the gaps.

Related

Using jQuery and Math.random() to select nested objects properties

I'm creating a random quote machine that will present a random quote from various philosophers.
I have an object literal with nested objects containing philosophers and their quotes. Using jQuery functions and Math.random(), how can I select a random quote from my object literal structure? Is there a better way to organize the data?
I've started with a jQuery closure that will display a designated quote that I'd like to modify using Math.random().
Looking for explanations to solutions as I'm a beginner. Thanks in advance.
Example object literal:
var quotes =
{
awatts: {
name: "Alan Watts",
quote: "The only way to make sense out of change is to plunge into it, move with it, and join the dance."
},
etolle: {
name: "Eckhart Tolle",
quote: "Realize deeply that the present moment is all you ever have."
},
tmckenna: {
name: "Terrence Mckenna",
quote: "“The cost of sanity in this society, is a certain level of alienation” "
}
};
Example jQuery functions with single quote selected:
$(document).ready(function() {
$('.mybutton').click(function() {
$('#quote').html(quotes.awatts.quote);
});
});
The structure of the data seems fine. You could use an array, but an object isn't a problem.
You'd get the keys from the object, and then pick a random key
var quotes = {
awatts: {
name: "Alan Watts",
quote: "The only way to make sense out of change is to plunge into it, move with it, and join the dance."
},
etolle: {
name: "Eckhart Tolle",
quote: "Realize deeply that the present moment is all you ever have."
},
tmckenna: {
name: "Terrence Mckenna",
quote: "“The cost of sanity in this society, is a certain level of alienation” "
}
};
$('.mybutton').click(function() {
var keys = Object.keys(quotes);
var rand = keys[Math.floor(Math.random() * keys.length)];
$('#quote').html(quotes[rand].quote);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="mybutton">Quote</button>
<br><br>
<div id="quote"></div>
If you can make your quotes object an array, the following would do the trick. Change your array
var quotes = [
{
name: "Alan Watts",
quote: "The only way to make sense out of change is to plunge into it, move with it, and join the dance."
},
{
name: "Eckhart Tolle",
quote: "Realize deeply that the present moment is all you ever have."
},
{
name: "Terrence Mckenna",
quote: "“The cost of sanity in this society, is a certain level of alienation” "
}
];
Set the max and min (to set the upper and lower limits for the random number)
var max = quotes.length, min = 0;
Generate a random number
var rand = Math.random() * (max - min) + min;
On the click event use the random number to choose your random quote
$('#quote').html(quotes[rand]quote);
I have not tested the code. Hope this will get you going :-)

Fuzzy string match + amount match in node.js

Hi i need to order the data according to the fuzzy matching of 2 variables
Consider i have a string :"pet" and Amount 50
I have an object array as like below:
[{"des":"permanent","amount":100}, {"des":"petrol","amount":1000}]
I need an array as below
[{"des":"petrol","amount":100}, {"des":"permanent","amount":1000}] if suppose petrol is highest matching also its nearer to the value 50.
I used fuzzy npm package as follows:
var options = {
extract: function(el) { return el.description; }
};
var results = fuzzy.filter(description, res, options);
But here i can check for only string, but how can i do also for amount?? Thanks in advance
Your specification isn't entirely clear, but it seems like you want sorting (changing the order of elements based on some critieria) rather than filtering (removing elements based on some criteria).
There are two possibilities:
You want to sort by fuzzy score on the des string value, then break ties by the amount proximity.
You want to sort by some aggregate weight between the fuzzy des score and by the amount proximity.
Here's the first option:
const search = {des: "pet", amount: 10};
const data = [
{des: "pet", amount: 1000},
{des: "petrol", amount: 38},
{des: "petrol", amount: -17},
{des: "pets", amount: 9},
{des: "pet", amount: 999},
];
data.sort((a, b) => {
const {score: desA} = fuzzy.match(search.des, a.des);
const {score: desB} = fuzzy.match(search.des, b.des);
if (desA !== desB) {
return desB - desA;
}
return Math.abs(search.amount - a.amount) -
Math.abs(search.amount - b.amount);
});
console.log(data);
<script src="https://unpkg.com/fuzzy#0.1.3/lib/fuzzy.js"></script>
The second option is more involved, so I'll describe it on a high level. Use fuzzy.match to figure out the score for each des string, figure out how close amount is to the search target, normalize these to the same scale (probably 0 through 1), then weigh the scores by some amount to give a final score. Sort on the final score for each element.
Be careful: fuzzy.match().score returns Infinity for perfect matches, so you might want to convert that to 0 for certain operations.

Complex array ordering

Suppose I have the following array:
var articles = [
{
id: 7989546,
tags: [
"98#6",
"107#6",
"558234#7"
]
},
//...
]
Each element of this array represents (partially) some kind of content in our website. It has an id and is tagged with people (#6) and/or topics (#7).
The user is going to be provided a cookie containing the suggested or recommended tags, like this:
var suggestions = [
"46#6",
"107#6",
"48793#7"
]
Consider these tags like suggestions that will be shown to the end user, like "Maybe you are interesed in reading..."
The suggestions array is already ordered by tag prioritiy. This means, that the first tag is more relevant to the user than the second tag.
Now, what I want to do is to order my articles array in the same way, that is, by tag priority.
No filters should be applied as the articles array is guaranteed to have elements that have at least one tag from the suggestions array.
If I have an article with tags: [ "98#6", "107#6", 558234#7" ] and another one with tags: [ "46#6", "36987#7" ], I want the latter to be first, because the tag 46#6 has more priority than 107#6 in the suggestions array.
How can I achieve this kind of ordering (using two arrays)?
Note: jQuery solutions are gladly accepted.
jsFiddle Demo
Just make your own sort function and then use .indexOf in order to check for tag existence. The issue that you are going to have to decide to handle on your own is what makes the most sense for collisions. If an article is tagged with a priority 1 tag, but another article is tagged with 3 lower priority tags, who gets precedence? There is some logic involved there and in my suggested solution I simply just take a total of the priority by using the length of suggestions and summing the priorities. This can be adapted to give a different type of collision detection if you wish, but the approach will be basically the same.
Step 1: Create the compare function
This is going to order the array descending base on the result from tagCount. Which is to say that if tagCount returns a value of 6 for right, and a value of 3 for left, then 6 is ordered first.
var compareFn = function(left,right){
return tagCount(right.tags) - tagCount(left.tags);
};
Step 2: Create the tagCount "algorithm" for determining priority
This simply gives precedence to the earliest occurring match, but will also give some weight to multiple later occurring matches. It does this by taking the matched index subtracted from the length of the match array (suggestions). So if there are 5 suggestions, and the first suggestion is matched, then that is going to end up being a value of 5 (length=5 - index=0).
var tagCount = function(tags){
var count = 0;
for(var i = 0; i < tags.length; i++){
var weight = suggestions.indexOf(tags[i]);
if(weight > -1)
count += tags.length - weight;
}
return count;
}
Stack Snippet
var articles = [
{
id: 7989546,
tags: [
"107#6",
"558234#7"
]
},
{
id: 756,
tags: [
"98#6",
"558234#7"
]
},
{
id: 79876,
tags: [
"98#6",
"107#6",
"558234#7"
]
},
{
id: 7984576,
tags: [
"98#6",
"107#6",
"46#6"
]
}
];
var suggestions = [
"46#6",
"107#6",
"48793#7"
];
var compareFn = function(left,right){
return tagCount(right.tags) - tagCount(left.tags);
};
var tagCount = function(tags){
var count = 0;
for(var i = 0; i < tags.length; i++){
var weight = suggestions.indexOf(tags[i]);
if(weight > -1)
count += tags.length - weight;
}
return count;
}
var a = articles.sort(compareFn);
console.log(a);
document.querySelector("#d").innerHTML = JSON.stringify(a);
<div id="d"></div>
My approach: Sort by sum of relevance score
Give you have:
var articles = [
{
id: 7989546,
tags: [
"98#6",
"107#6",
"558234#7"
]
},
{
id: 8000000,
tags: [
"107#6",
"107#10",
"558234#7",
"5555#1"
]
},
{
id: 8333000,
tags: [
"46#6",
"107#6",
"666234#7",
"107#6"
]
}
];
var suggestions = [
"46#6",
"107#6",
"48793#7"
];
And you want to sort articles by tags whereas tag ranks are defined in suggestions. One simple approach would be:
Step 1) For each article, get index of each tag exists in the suggestion. If it doesn't exist, discard.
Given suggestions ["a","b","c"]
Article tags ["a","b","zzzz","yyyy"]
Will be mapped to index [0,1] (last two tags are discarded because they do not exist in suggestion list)
Step 2) Calculate degree of relevance. Higher-ranked tag (smaller index) yields greater value (see function degreeOfRelevance() below).
Step 3) Sum the total degree of relevance and sort by this value. Thus, the article which contains higher ranked tags (based on suggestions) will yield higher total score.
Quick example:
article <100> with tags: [a,b,c]
article <200> with tags: [b,c]
article <300> with tags: [c,d,e,f]
Given suggestions: [a,b,c]
The articles will be mapped to scores:
article <100> index : [0,1] ===> sum score: 3+2 = 5
article <200> index : [1] ===> sum score: 2
article <300> index : [2] ===> sum score: 1
Therefore, the article <100> is ranked the most relevant document when sorted by score
And below is the working code for this approach:
function suggest(articles, suggestions){
function degreeOfRelavance(t){
return suggestions.length - suggestions.indexOf(t);
}
function weight(tags){
return (tags.map(degreeOfRelavance)).reduce(function(a,b){
return a+b
},0);
}
function relatedTags(a){
return a.tags.filter(function(t){
return suggestions.indexOf(t)>=0
});
}
articles.sort(function(a,b){
return weight(relatedTags(a)) < weight(relatedTags(b))
});
return articles;
}
// See the output
console.log(suggest(articles,suggestions));

One array or many? (hash table)

I've an array that is being used to store the conversion factors for a conversion program I'm currently working on.
A short Example:
var Length =
{
"lengthsA" :
{
"inch" : 0.0254,
"yard" : 0.9144,
"mile" : 1609.344,
"foot" : 0.3048,
"metres": 1
}}
This will become much bigger and there are many more of them.
It seems I have two options. I can either declare many arrays, one for each conversion type and in the function use and if else to dictate which one should be called upon for the conversion. The alternative is to use one huge array that stores everything. This would nullify the need for an if else and also remove the need to declare many arrays but at the cost of combining everything into what could become one big mess.
I'm in favour of the first option, mainly because I like modularity and it'd be easier for debugging / editing.
I'm also concerned about speed and access time. With one large array would there be an impact seeing as I'm using keys to determine what values are called. Key above would be "lengthsA"
Thanks.
If I were doing this project, I'd definitely use a hierarchical structure. I might start with something like this:
var conversions = {
length : {
lengthsA : {
inch : 0.0254,
yard : 0.9144,
mile : 1609.344,
foot : 0.3048,
metres: 1
},
lengthsB : {
. . .
}
},
mass : {
},
. . .
}
The structure is: conversions.<category>.<conversion_group>.<unit_name>. It's probably as easy to maintain as any other structure.
You might consider adding a property reference that would indicate the name of the unit that should be the reference (e.g., reference : "metres" in the case of lengthsA). I'd also be more consistent about unit names ("inch" is singular; "metres" is plural). Depending on your application, you might also want to have each conversion be a structure with a value and an uncertainty. (Some conversion factors are exact; others are not.)
Hard to say without knowing all the details of your program, but I wouldn't use hierarchical objects for storing units, but rather a flat array, similar to a SQL table:
units = [
{ category: "length", name: "inch" , value: 0.0254 },
{ category: "length", name: "yard" , value: 0.9144 },
{ category: "length", name: "mile" , value: 1609.344 },
{ category: "length", name: "foot" , value: 0.3048 },
{ category: "length", name: "meter", value: 1 }
]
You will need a couple of utility functions to find items in this table (like getUnitsByCategory), but once you've got it, you'll find this structure much easier to work with. Uniformity is the king!
if you define variable for javascript so..
var inch=0.0254,
yard=0.9144
youcan write
<option>inch</option>
and acces it with
window[document.select.textContent]
it's much faster but the code would be much longer.
In your case the readability is more important
so yes create a multidiminsional object.(groups)
it's also easier to access the values.
obj={
"length":{
inches:0.0254,
miles:1609.344,
},
"weight":{
kg:1
}
}
so you can access it by
obj.length.inches
or
obj['length']['inches']
and write
window.onload=function(){
var obj={
length:{
inches:0.0254,
miles:1609.344,
}
}
var select1=document.createElement('select'),
select2=null,
f=document.createDocumentFragment(),
input=document.createElement('input'),
convert=document.createElement('button');
for(var a in obj.length){
f.appendChild(document.createElement('option')).textContent=a;// easyway to access
}
select1.appendChild(f);
select2=select1.cloneNode(true);
input.type='text';
convert.textContent='Convert';
convert.addEventListener('click',function(e){
console.log(
input.value,
obj.length[select1.textContent],// easyway to access
obj.length[select2.textContent]// easyway to access
)
},false);
var bdy=document.body
bdy.appendChild(input);
bdy.appendChild(select1);
bdy.appendChild(select2);
bdy.appendChild(convert);
}

Sort, group list in Sencha Touch 2.1 by first letter after hyphen if present

I have dataset to be used in a list using Sencha Touch 2.1 in which most items begin with a prefix (E.g. P-, S-, CSV- etc.). Some, however, do not.
The prefix is not relevant for sorting and grouping the list (as the prefix is not what users will be looking for). If all items had prefixes and all prefixes were single letters I would just sort by third letter. As this is not the case I really have no idea how to continue.
Thus I want to set up a conditional grouping and sorting function along the lines of:
If {name} contains hyphen: sort/group by first letter after first hyphen, else: sort by first letter
Also, some of the names will be identical without the prefix (e.g P-Albumin, U-Albumin) if the rest of the string is identical I'd want the rows with "Albumin" to be sorted their prefixes. Also, even with prefixes some strings would be the same and another field e.g. "age" would differ so
{ name: 'P-Albumin', age: '40 - 50' },
{ name: 'P-Albumin', age: '20 - 30' },
{ name: 'CSV-Albumin', age: '30' },
{ name: 'ASAT', age: '30'},
Would be grouped together under the letter A, and sorted so that the row with age equalling 20 - 30 would precede the one equalling 40 - 50, and the row with the prefix CSV- in turn would precede them both and ASAT remaining last.
I appreciate any tips, pointers, help, advice I can get.
For sorting by names you can create a converted field in the model.
Ext.define('MyApp.model.MyModel', {
extend : 'Ext.data.Model',
config : {
fields : ['name', 'age',
{
name : 'formattedName',
type : 'string',
convert : function(v, record) {
var unformattedName = record.get('name');
if (unformattedName.indexOf("-") != -1) {
return unformattedName.substring(unformattedName
.indexOf("-"));
} else {
return unformattedName;
}
}
}]
}
});
Now you can set the sort-priority in your store config
Ext.define('MyApp.store.MyStore', {
extend : 'Ext.data.Store',
config : {
model : "MyApp.model.MyModel",
sorters: 'formattedName, name, age'
...
}
});
The store first looks at the formatted name without the prefix, then the complete name including the prefix and finally the age.

Categories

Resources