I am trying to find all combinations and create an array of string from an array. For example:
var text_array = [["h"],["e","è","é","ê","ë"],["l"],["l"],["o","ò","ó","ô","õ"]]
output = ["hello","hèllo","héllo",etc...]
I have tried several ways but they all seemed extremely long winded and I think I'm just maybe missing a function I don't know about.
One way to abstract the implementation from the number of characters is to incrementally build the list of final values and the values themselves. You start with an empty result, [""]. Then you take the first list of variants and add each variant to every result we have so far, producing a new list of intermediate results, ["h"].
The second list of variants has multiple elements, so after this iteration you'll have this list of results, ["he", "hè", "hé", "hê", "hë"]. And so on.
In pseudo-code, it could look like this:
results = [""]
for each list_of_variants in text_array {
new_results = []
for each variant in list_of_variants {
for each result in results {
new_result.push(result + variant)
}
}
results = new_results
}
Related
Bit of a lengthy one so those of you who like a challenge (or I'm simply not knowledgeable enough - hopefully it's an easy solution!) read on!
(skip to the actual question part to skip the explanation and what I've tried)
Problem
I have a site that has a dataset that contains an object with multiple objects inside. Each of those objects contains an array, and within that array there are multiple objects. (yes this is painful but its from an API and I need to use this dataset without changing or modifying it.) I am trying to filter the dataset based of the key-value pairs in the final object. However, I have multiple filters being executed at once.
Example of Path before looping which retrieves the key-value pair needed for one hall.
["Hamilton Hall"]["Hire Options"][2].Commercial
After Looping Path of required key-value pair for all halls, not just one (the hall identifier is stored):
[0]["Hire Options"][2].Commercial
Looping allows me to check each hall for a specific key-value pair (kind of like map or forEach, but for an object).
After getting that out of the way back to the question.
How would I go about filtering which of the looped objects are displayed?
What I have Tried
(userInput is defined elsewhere - this happens on a btn click btw)
let results = Object.keys(halls);
for (key of results) {
let weekend = [halls[ `${key}` ][ 'Hire Options' ][4][ 'Weekend function' ]];
if(userInput == weekend) {
outputAll([halls[ `${key}` ]]);
}
}
That filters it fine. However, I run into an issue here. I want to filter by multiple queries, and naturally adding an AND into the if statement doesn't work. I also dont want to have 10 if statements (I have 10+ filters of various data types I need to sort by).
I have recently heard of ternary operators, but do not know enough about them to know if that is the correct thing to do? If so, how? Also had a brief loook at switches, but doesnt seem to look like what I want (correct me if I am wrong.)
Actual Question minus the babble/explanation
Is there a way for me to dynamically modify an if statements conditions? Such as adding or removing conditions of an if statement? Such as if the filter for 'a' is set to off, remove the AND condition for 'a' in the if statement? This would mean that the results would only filter with the active filters.
Any help, comments or 'why haven't you tried this' remark are greatly appreciated!
Thanks!
Just for extra reference, here is the code for retrieving each of the objects from the first object as it loops through them:
(Looping Code)
halls = data[ 'Halls' ];
let results = Object.keys(halls);
for (key of results) {
let arr = [halls[ `${key}` ]];
outputAll(arr);
}
You can use Array.filter on the keys array - you can structure the logic for a match how you like - just make it return true if a match is found and the element needs to be displayed.
let results = Object.keys(halls);
results.filter(key => {
if (userInput == halls[key]['Hire Options'][4]['Weekend function']) {
return true;
}
if (some other condition you want to match) {
return true;
}
return false;
}).forEach(key => outputAll([halls[key]]));
Good Morning,
I have a little logic's question I cant quiet wrap my head around. I have an array of values I get from a forEach which returns an array like this.
"events": [["IDLING:END"],["TOWING:END"]],
I need to add this to a single variable separated by n comma. This events type can have multiple entries for example, it could also have an extra SPEED:END entry etc. So I need it to be like...
let eventResult = 'IDLING:END,TOWING:END,SPEED:END'
So now my question: How do I add these and then check if there is any extra entries and add all of the new entries only once. I have multiple gps positions with the exact same data and I need to add every entry only once, but as I said this can potentially have more entries at any given moment, or should I say extra values.
I hope my explanation is clear.
Warm Regards
I would have done it in the following way. I also agree that there are various ways to remove duplicates.
let events = [["a:a"], ["b:b"], ["a:a"]];
let arrToJoin = [];
const flatArray = events.flat();
flatArray.forEach((e) => {
if (arrToJoin.findIndex((a) => a === e) === -1) {
arrToJoin.push(e);
}
});
console.log(arrToJoin.join(","));
db = new Array("myserver", "myfolder\\mydb.nsf")
dir = getComponent("Dir").value;
div = getComponent("Div").value;
lu = #DbLookup(db, "ManagerAccess", dir + "PP" + div, "DTManagers");
var a = [];
a.push(lu);
var item:NotesItem = docBackEnd.replaceItemValue('FormReaders', #Unique(a));
item.setReaders(true);
That code is on the querySaveDocument ssjs. The result I get from the #DbLookup (when I put in a computed field) look like this:
Pedro Martinez,Manny Ramirez,David Ortiz,Terry Francona
I tried doing an #Explode(#Implode) thing on it, but it doesn't seem to work.
The error I get in the browser just tells me that the replaceItemValue line is broken.
To test it, I pushed several strings one at a time, and it worked correctly populating my FormReaders field with the multiple entries.
What am I doing wrong?
I see several problems here:
A. In cases as described by you #Dblookup in fact would return an array. If you push an array into a plain computedField control it will exactly look as that you wrote:
value1, value2, ..., valueN
A computedField doesn't know anything about multiple values etc, it just can display strings, or data that can be converted to strings.
If you want to test the return value you could try to return something like lu[0]; you then should receive the array's 1st element, or a runtime error, if lu is NOT an array. Or you could ask for the array's size using lu.length. That returns the number of array elements, or the number of characters if it's just a plain string.
B. your code contains these two lines:
var a = [];
a.push(lu);
By that you create an empty array, then push lu[] to the first element of a[]. The result is something like this:
a[0] = [value1, value2, ..., valueN],
i.e. a is an array where the first element contains another array. Since you don't want that, just use #Unique(lu) in your replaceItemValue-method.
C. I don't see why replaceItemValue would throw an error here, apart from what I wrote in topic B. Give it a try by writing lu directly to the item (first without #Unique). That should work.
D. for completeness: in the first line you used "new Array". A much better way to define your db parameters is
var db = ["myserver", "myfolder/mydb.nsf"];
(see Tim Tripcony's comment in your recent question, or see his blog entry at http://www.timtripcony.com/blog.nsf/d6plinks/TTRY-9AN5ZK)
I am using a regex to find dupliates in a list. It is only a short comma seperated list, and performance is not an issue, so there is no need to tell me I should not use regex for those reasons.
// returns a match because some is repeated
"some,thing,here,some,whatever".match(/(^|,)(.+?)(,|,.+,)\2(,|$)/g)
Questions...
Can this regex be improved?
Does it cover all possible scenarios where comma is not in the seperated strings
Is there a better (preferably more readable and more efficient) way to do this?
I don't see the purpose of using regexes here, unless you like unimaginable pain. If I had to find duplicates I would
Obtain an array of words
var words = "...".split(',');
optionally lowercase everything, if you feel like doing that
sort the array
words.sort()
Duplicates should now all be in consecutive positions of the array.
As an extra advantage, I`m pretty sure this would be vastly more efficient than a regex version.
If I wanted to find dups in a comma separated list, I'd do it like this, using the hash capabilities of an object to accumulate unique values and detect dups:
function getDups(list) {
var data = list.split(",");
var uniques = {}, dups = {}, item, uniqueList = [];
for (var i = 0; i < data.length; i++) {
item = data[i];
if (uniques[item]) {
// found dup
dups[item] = true;
} else {
// found unique item
uniques[item] = true;
}
}
// at the end here, you'd have an object called uniques with all the unique items in it
// you could turn that back into an array easily if you wanted to
// Since it uses the object hash for dup detection, it scales to large numbers of items just fine
// you can return whatever you want here (a new list, a list of dups, etc...)
// in this implementation, I chose to return an array of unique values
for (var key in uniques) {
uniqueList.push(key);
}
return(uniqueList); // return array of unique values
}
var list = "some,thing,here,some,whatever";
getDups(list);
Here's a jsFiddle that shows it working: http://jsfiddle.net/jfriend00/NGQCz/
This type of implementation scales well with large numbers of words because the dup detection is relatively efficient.
Is there any way efficiently to join JSON data? Suppose we have two JSON datasets:
{"COLORS":[[1,red],[2,yellow],[3,orange]]}
{"FRUITS":[[1,apple],[2,banana],[3,orange]]}
And I want to turn this into the following client side:
{"NEW_FRUITS":[[1,apple,red],[2,banana,yellow],[3,orange,orange]]}
Keep in mind there will be thousands of records here with much more complex data structures. jQuery and vanilla javascript are both fine. Also keep in mind that there may be colors without fruits and fruits without colors.
NOTE: For the sake of simplicity, let's say that the two datasets are both in the same order, but the second dataset may have gaps.
Alasql JavaScript SQL library does exactly what you need in one line:
<script src="alasql.min.js"></script>
<script>
var data = { COLORS: [[1,"red"],[2,"yellow"],[3,"orange"]],
FRUITS: [[1,"apple"],[2,"banana"],[3,"orange"]]};
data.NEW_FRUITS = alasql('SELECT MATRIX COLORS.[0], COLORS.[1], FRUITS.[1] AS [2] \
FROM ? AS COLORS JOIN ? AS FRUITS ON COLORS.[0] = FRUITS.[0]',
[data.COLORS, data.FRUITS]);
</script>
You can play with this example in jsFiddle.
This is a SQL expression, where:
SELECT - select operator
MATRIX - modifier, whci converts resultset from array of objects to array of arrays
COLORS.[0] - first column of COLORS array, etc.
FRUITS.1 AS 2 - the second column of array FRUITS will be stored as third column in resulting recordset
FROM ? AS COLORS - data array from parameters named COLORS in SQL statement
JOIN ? ON ... - join
[data.COLORS, data.FRUITS] - parameters with data arrays
The fact that there will be thousands of inputs and the keys are not necessarily ordered means your best bet (at least for large objects) is to sort by key first. For objects of size less than about 5 or so, a brute-force n^2 approach should suffice.
Then you can write out the result by walking through the two arrays in parallel, appending new "records" to your output as you go. This sort-then-merge idea is a relatively powerful one and is used frequently. If you do not want to sort first, you can add elements to a priority queue, merging as you go. The sort-then-merge approach is conceptually simpler to code perhaps; if performance matters you should do some profiling.
For colors-without-fruits and fruits-without-colors, I assume writing null for the missing value is sufficient. If the same key appears more than once in either color or fruit, you can either choose one arbitrarily, or throw an exception.
ADDENDUM I did a fiddle as well: http://jsfiddle.net/LuLMz/. It makes no assumptions on the order of the keys nor any assumptions on the relative lengths of the arrays. The only assumptions are the names of the fields and the fact that each subarray has two elements.
There is not a direct way, but you can write logic to get a combined object like this. Since "apple, red, banana...." are all strings, they should be wrapped in a single or double quote.
If you can match the COLORS and FRUITS config array by adding null values for missing items then you can use this approach.
Working demo
var colors = {"COLORS":[[1,'red'],[2,'yellow'],[3,'orange']]}
var fruits = {"FRUITS":[[1,'apple'],[2,'banana'],[3,'orange']]}
var newFruits = {"NEW_FRUITS": [] }
//Just to make sure both arrays are the same size, otherwise the logic will break
if(colors.COLORS.length == fruits.FRUITS.length){
var temp;
$.each(fruits.FRUITS, function(i){
temp = this;
temp.push(colors.COLORS[i][2]);
newFruits.NEW_FRUITS.push(temp);
});
}
Alternatively, if you can create colors and fruits configs as an array of objects, instead of an array of arrays, you can try this solution. The sequence of the elements is irrelevant here, but the array size should still match.
Working demo
var colors = {"COLORS":[ {"1": 'red'}, { "2": 'yellow'}, {"3":'orange'}]}
var fruits = {"FRUITS":[ {"1":'apple'}, { "2": 'banana'}, {"3":'orange'}]}
var newFruits = {"NEW_FRUITS": [] }
if(colors.COLORS.length == fruits.FRUITS.length){
var temp, first;
$.each(fruits.FRUITS, function(i){
for(first in this)break;
temp = {};
temp[first] = [];
temp[first].push(this[first]);
temp[first].push(colors.COLORS[i][first]);
newFruits.NEW_FRUITS.push(temp);
});
}