You are given an array of desired filenames in the order of their
creation. Since two files cannot have equal names, the one which comes
later will have an addition to its name in a form of (k), where k is
the smallest positive integer such that the obtained name is not used
yet.
Return an array of names that will be given to the files.
Example
For names = ["doc", "doc", "image", "doc(1)", "doc"], the output
should be fileNaming(names) = ["doc", "doc(1)", "image", "doc(1)(1)",
"doc(2)"].
One person posted this solution:
const fileNaming = names => {
const used = {};
return names.map(name => {
let newName = name;
while (used[newName]) {
newName = `${name}(${used[name]++})`;
}
used[newName] = 1;
return newName;
});
};
I'm having a hard time understanding the while block's condition.
used is an empty object.
newName is a new variable that is equal to the current item in the names array.
How does used[newName] resolve to a number? used is never set to anything other then an empty object.
This is the console output for console.log(used[newName])
Using this input:
["dd",
"dd(1)",
"dd(2)",
"dd",
"dd(1)",
"dd(1)(2)",
"dd(1)(1)",
"dd",
"dd(1)"]
In JavaScript, {} is an empty object - and as such, it can contain any number of key-value pairs. A key that is not defined has the value undefined, which evaluates to false when tested. However, any non-zero, non-NaN numerical value will evaluate to true:
console.log({}["a key that does not exist"]) // undefined
while (undefined) {
console.log("this should never be printed"); // never executes
}
while ({}["a key that does not exist"]) {
console.log("this should never be printed"); // never executes
}
if (1) {
console.log("positive numbers are true"); // writes to console
}
You can use objects as maps (even though you can also use actual maps instead in newer code)
A simpler version of the above program would have written
return names.map(name => {
let newName = name;
while (used[newName] !== undefined) { // tests for "not undefined"
newName = `${name}(${used[name]})`; // uses current value
used[name] = used[name] + 1; // sets a larger value
}
used[newName] = 1; // sets a value
return newName;
});
Related
Today as I read the PrimeNg's source code, noticed one thing. The author of one utils class (ObjectUtils) in some cases initialized the arrays, but in other ones not.
Example 1 from source code:
public static generateSelectItems(val: any[], field: string): SelectItem[] {
let selectItems: SelectItem[];
if(val && val.length) {
selectItems = [];
for(let item of val) {
selectItems.push({label: this.resolveFieldData(item, field), value: item});
}
}
return selectItems;
}
Example 2 from source code:
public static filter(value: any[], fields: any[], filterValue: string) {
let filteredItems: any[] = [];
let filterText = this.removeAccents(filterValue).toLowerCase();
if(value) {
for(let item of value) {
for(let field of fields) {
let fieldValue = this.removeAccents(String(this.resolveFieldData(item, field))).toLowerCase();
if(fieldValue.indexOf(filterText) > -1) {
filteredItems.push(item);
break;
}
}
}
}
return filteredItems;
}
In second example he initialized the array filteredItems, but in first one does not (selectItems array). I'm wondering why he did so and if there is any best practices regarding this.
This line:
let selectItems: SelectItem[];
declares a variable, but does not create an array. (It doesn't initialize the variable with anything.) Later, the array is created using [], here:
selectItems = [];
// -----------^^
...and then assigned to the variable.
This line:
let filteredItems: any[] = [];
...combines those two steps by providing a variable initializer.
The key thing to understand is that selectItems in the first example doesn't contain anything, at all, until it has something assigned to it. So it isn't that the programmer "hasn't initialized the array," it's that he/she hasn't initialized the variable.
You don't have to initialize a variable when declaring it. Both let and var declarations without an initializer initialize the variable to undefined (at different times, but that's not important here). (You do need to initialize a constant declared with const when declaring it, since you can't assign to it afterward.)
In a comment you asked:
But when this if(val && val.length) fails in first example, then the function will return undefined. Won't be better if it returns let say an empty array?
That depends purely on what the programmer wants to have happen when val is falsy or has a falsy length. I'm sure there are use cases for returning undefined and for returning an empty array.
You may be wondering, though, about returning undefined when the type annotation on the function says it returns SelectItem[]. Remember that by default, null and undefined are effectively members of every type. You can turn that off with the strictNullChecks option, which is documented as:
In strict null checking mode, the null and undefined values are not in the domain of every type and are only assignable to themselves and any (the one exception being that undefined is also assignable to void).
strictNullChecks would indeed have made that function an error. Compare this code:
function foo(bar: boolean) : Date {
let x : Date;
if (bar) {
x = new Date();
}
return x;
}
foo(Math.random() < 0.5);
Try it in the playground using the Options button to enable/disable
strictNullChecks: TypeScript flags an error when it's enabled.
I have an application that can turns a tex file into a JavaScript object, with key-value pairs. The key being the word and the value being the number of times it has appeared in the text file. Let's go through it together:
FormatText.prototype.toDowncase = function() {
return this._data = this._data.toLowerCase();
};
This turns the words to lowercase
FormatText.prototype.deleteWords = function() {
return this._data = this._data.replace(/\W/g, " ");
};
This replaces all non-words with a space
FormatText.prototype.splitWords = function() {
return this._data = this._data.split(/\s+/);
};
This turns the string in an array and splits at each delimiter
FormatText.prototype.filterEntries = function() {
return this._data = this._data.filter(v => !!v);
};
This one above I have no clue what it does.
FormatText.prototype.countWords = function() {
return this._data = this._data.reduce((dict, v) => {dict[v] = v in dict ? dict[v] + 1 : 1; return dict}, {});
}
Could someone explain this one, however I will get it a try:
This one takes the array and passed the method 'reduce' with two arguments. It counts how many times each individual word has appeared and returns an object with the 'key-value' pairs described at the beginning of this question.
v => !!v means take v, and coerce it to a Boolean type by applying NOT twice. So the filter function is basically removing any falsey values (0, null, undefined) from this._data.
countWords is counting the number of times each word occurs in this._data - it is going through the array and adding 1 to the count if the word has been encountered before, or returning 1 if the word has not been encountered before. It returns an object with the words as keys and the counts as values.
As a note, these functions change the type of this._data, from a string, to an array, to an object. That may cause bugs to appear if e.g. you run the same method twice
Why not just return the value, without NOT NOT, like
v => v
because for filtering the value coerces to a boolean value.
From Array#filter:
Description
filter() calls a provided callback function once for each element in an array, and constructs a new array of all the values for which callback returns a value that coerces to true. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values. Array elements which do not pass the callback test are simply skipped, and are not included in the new array.
In this case the double exclamation mark is useless: the value returned from the callback in filter(callback) is then coerced to a boolean automatically, so no need to do it using double exclamation mark. The following lines are equivalent:
.filter(v => !!v)
.filter(v => v)
.filter(Boolean)
This one above I have no clue what it does.
The javascript operator ! (logical not) performs a type coercion (to boolean) on its argument. So applied twice you somehow convert any type to a boolean value which gives you whether it is falsy or truthy.
This is interesting when you want to apply a condition to different types whose semantic is more or less "no value". For example:
!!('') //false
!!(0) //false
!!null //false
!!undefined //false
Could someone explain this one, however I will get it a try
reduce is method of the array prototype which allows to iterate over a collection while aggregating value.
In your specific example the aggregator is a dictionary which maps a word to a count (number of appearance). So if the word is not present in the dictionary it creates a key for this word with a counter initialized to 1 otherwise it increments the counter (if word already present).
A equivalent could be
const countWords = function (words = [], dictionary = {}) {
if(words.length === 0) {
return dictionary;
}
const word = words.pop(); //remove and read the word at the end of the array
if(word in dictionary) {//if key is present in the dictionary
dictionary[word] += 1; // increment
else {
dictionary[word] = 1; // start a counter for new keyword
}
return countWords(words, dictionary);
}
So I was working with a colleague who showed me how i could solve a particular problem: how to get a flat object into a nested object. The object properties are named in such a way that they can be sliced into their relevant key named and then nested. His solution works beautifully, but when I ran through his code myself later I couldn't understand how it works.
I'm essentially taking a excel worksheet and creating json from it but for argument sake i'll remove the excel parts and just add the example structure which comes out of the excel parser:
//Example data
var result = {
frame1.title: "heading",
frame1.division: "first",
frame1.data[0].month: "Jan",
frame1.data[0].value: "54",
}
function deepInsert (o, path, value) {
let next, cur = o
path.forEach((p,i) => {
next = cur[p]
if (i == path.length -1) {
cur[p] = value
} else {
if (!next) {
next = cur[p] = {}
}
cur = next
}
})
}
function processWorkbook () {
const result = json.map(item => {
var o = {foo: "bar"}
Object.keys(item).forEach(prop => {
deepInsert(o, prop.split('.'), item[prop])
console.log(JSON.stringify(o, 0, ' '));
})
return o
})
console.log(JSON.stringify(result, 0, ' '))
}
From what I can tell it looks like hes passing in 'o', which is a blank object, then the loop in the deepInsert function is assigning data to not the param, but the object in the calling function, because everytime through the loop, my console log shows more being added to the object.
I also don't understand this part: next = cur[p] = {}. For some reason a triple assignment throws me an error in the chrome repl but not in that function? Im just so confused, any help would be great!
The function deepInsert recives the following params:
An Object (it will be modified)
The array of path for the value( 'foo.bar.x' needs to become ['foo','bar', 'x'] )
The value to be inserted
and does this:
Iterates on the path Array
if the current path iteration isn't the last, it will Initialize a
new Object on it.
if the current path IS the last one, the passed value is set to it.
The function processWorkbook just iterates on the object keys to send the parameters to the deepInsert function. This could be done directly on the deepInsert.
And that's it. The problem is the function has unused variables and complicated code. A more simple and documented function:
function unnestObject(obj = {}) {
let newObject = {}, //The object to return
current; // the object position holder
for (var key in obj) { // iterate on recived object keys
current = newObject // Makes the current object the new Object root
let path = key.split('.') // Split the current key
path.forEach((p, i) => { // iterate on the key paths
if ((path.length - 1) !== i) //if the path isn't the last one
current[p] = current[p] || {} // initialize a new object on that path (if a object was previously initialized, it is preserved)
else //if the path is the last one
current[p] = obj[key] // sets the value of the initial object key
current = current[p] // Updates the current to the next node
})
}
return newObject; //returns the new object
}
//Example data [DOESNT WORK WITH ARRAYS]
var data = {
"frame1.title": "heading",
"frame1.division": "first",
"frame1.data.month": "Jan",
"frame1.data.value": "54",
}
console.log(unnestObject(data))
// Prints
// {
// "frame1": {
// "title": "heading",
// "division": "first",
// "data": {
// "month": "Jan",
// "value": "54"
// }
// }
// }
Note: Both functions doesn't support arrays, if you pass something like {"foo.bar[0].value": 42}, foo.bar will be a object. You can detect the array [] keys and make it initialize an array instead of an object on the iteration
About the next = cur[p] = {}, you can assign one value to multiple variables at once. you can do foo = bar = 42, both will have 42.
You can also do foo = bar = {}. both will have pointers to the same object, if you change a value on one, another will already have the change.
This is very userful for get and initialize global values for instance
var foo = window.foo = window.foo || {bar: 42};
This line will make foo and window.foo recive the object on window.foo . if window.foo wasn't initialized yet, it will recive the new object.
I am working on a project that solves the classic "jumbled word" puzzle found in many newspapers. The basic idea of the project is that it accepts a scrambled word (no spaces or special characters), generates every permutation of the word, checks each permutation against a "dictionary" supplied by my professor, then adds each permutation that is actually an English word to an array that is then processed further to come up with the result.
Currently, I'm running into a problem that arises when I attempt to check if a permutation is in the "dictionary". The code below was provided by my professor and creates a "dictionary" from an external text file. According to him, dictionary[w] should return a number paired with the word that represents the word's frequency or "undefined" if the word is not in the dictionary.
function readDictionary() {
/**
* #type {string[]}
*/
const lines = fs.readFileSync("count_1w.txt", "utf-8").split("\n");
var line;
const dictionary = {};
for (line of lines) {
line = line.trim();
let array = line.split('\t');
if (array.length > 1) {
let word = array[0];
let count = array[1];
if (lexicon[word]) {
dictionary[word] = parseFloat(count);
}
}
}
return Object.freeze(dictionary);
}
function getDictionary() {
if (dictionary === null) {
dictionary = readDictionary();
}
return dictionary;
}
var dictionary = getDictionary();
The following code which I have written should return "true" if dictionary[letters] is not undefined...
function inDict(letters) {
if (dictionary[letters] !== undefined){
return true;
}
else{
return false;
}
}
...however in its current state it throws the TypeError in the title of this post, with 'eat' being the first permutation of the input that is generated. Note that in my actual code readDictionary(), getDictionary(), and var dictionary = getDictionary are all declared above inDict().
If more details are needed please feel free to ask. I've reached the end of my personal knowledge of JavaScript, and multiple Google searches have turned up nothing that has helped in my particular instance. Any suggestions or opinions are greatly appreciated!
The error message is clear: dictionary has the value undefined, so why is that?
The problem is that the function getDictionary returns undefined. The condition dictionary === null is never true because dictionary has the initial value undefined and undefined === null is false.
So what you are really doing is
var dictionary; // initial value is undefined
dictionary = dictionary;
which does nothing.
I don't see why you need getDictionary at all. Just initialize dictionary directly:
var dictionary = readDictionary();
Alternatively you could:
Initialize dictionary with null (but why would you?)
var dictionary = null;
dictionary = getDictionary();
Compare against undefined instead:
function getDictionary() {
if (dictionary === undefined) {
dictionary = readDictionary();
}
return dictionary;
}
Overall, getDictionary is poorly designed because it has an implicit dependency on dictionary but also returns a value.
This question already has answers here:
Javascript using prototype how can I set the value of "this" for a number?
(3 answers)
Closed 6 years ago.
I try to set a number directly from a prototype method.
Usually, a new value is returned.
this of a number object, is also an object. But I guess not a reference. (?)
I have this:
Number.prototype.bitSet = function(bit) {
return this | (1<<bit);
};
But want this:
Number.prototype.bitSet = function(bit) {
this.value = this | (1<<bit);
};
this.value is a pseudo property. Becuase this sould be a reference of the number and without that, you'll overwrite it. But the question is: Is this really a reference to the source number? Is it possible to do that? Assign the value directly to the number who called this method?
var num = 0;
num.bitSet(9);
console.log(num); // num = 512
Btw. chrome console prints [[PrimitiveValue]] for the number.
TL;DR - You can't do that, your initial version of bitSet is how you need to define it. You'll need to save its return value when you use it, e.g., x = x.bitSet(2). You can create your own mutable number object, though, if you like. (More on that below.)
Just for clarity (you probably know this): JavaScript has both number primitives and Number objects. Normally, you're dealing with primitives. The reason Number.prototype works is that a temporary object is created using the primitive's value when a method is called on it. Unless something explicitly saves the object, though, it's as though we were just dealing with primitives.
Numbers are not mutable in JavaScript.1 So your bitSet method cannot change the numeric value of what it's called on; instead, it has to return a new number with the changes made (e.g., your original version).
Note that even if you could change a Number object's value, you're almost never dealing with a number object in code outside functions you've assigned to Number.prototype. For instance:
Number.prototype.bitSet = function(bit) {
return this | (1<<bit);
};
var x = 32;
x = x.bitSet(2);
console.log(x); // 36
console.log(typeof x); // "number", not "object"
var o = new Number(36);
console.log(typeof o); // "object"
In the above, when x = x.bitSet(2); is executed, the number primitive is converted to a temporary Number object, your bitSet method is called, and then the result is whatever your bitSet method returns; unless bitSet does something to store this somewhere, the temporary object is then thrown away. (That's the theory; in fact, your JavaScript engine may well optimize away the object entirely, if it can determine that the code in your function only uses the number as though it were a primitive number.)
So suppose in my code above, we did something to change the state of the Number object in that x.bitSet(2) line. Since that object is temporary and not stored anywhere (unless we store it; it's not in x, x contains a primitive number), whatever we stored on the object would be lost. We can even prove that:
Number.prototype.test = function() {
this.foo = Math.random();
console.log("this.foo", this.foo); // some number
};
var x = 42;
x.test();
console.log(typeof x); // "number", not "object"
console.log("x.foo", x.foo); // undefined
this was definitely an object, we added a property to it and used that property. But x still had the primitive.
You could have your own mutable number type, though:
function MyNumber(value) {
this.value = typeof value === "number" ? value : 0;
}
MyNumber.prototype.bitSet = function(bit) {
this.value = this.value | (1 << bit);
};
MyNumber.prototype.valueOf = function() {
return this.value;
};
MyNumber.prototype.toString = function() {
return this.value.toString();
};
// Usage:
var m = new MyNumber(42);
m.bitSet(2);
console.log(String(m)); // "46"
var n = m + 5;
console.log(n); // 51
The valueOf function is called any time the JavaScript engine needs to convert your number object to a number. toString is called when the JavaScript engine needs to convert your number object to a string.
Or in ES2015:
class MyNumber {
constructor(value) {
this.value = typeof value === "number" ? value : 0;
}
bitSet(bit) {
this.value = this.value | (1 << bit);
}
valueOf() {
return this.value;
}
toString() {
return this.value.toString();
}
}
// Usage:
var m = new MyNumber(42);
m.bitSet(2);
console.log(String(m)); // "46"
var n = m + 5;
console.log(n); // 51
1 "Numbers are not mutable in JavaScript" Technically, that's not true. Primitive numbers are not mutable, but Number objects are — but their underlying numeric value (what the spec calls its [[NumberData]]) cannot be changed. (Number objects can have other properties with state that can be changed, just not their numeric value.) So "Numbers are not mutable in JavaScript" is a reasonable shorthand statement, if not perfectly correct.