JavaScript is in array [duplicate] - javascript

This question already has answers here:
How do I check if an array includes a value in JavaScript?
(60 answers)
Closed 28 days ago.
Let's say I have this:
var blockedTile = new Array("118", "67", "190", "43", "135", "520");
There's more array elements but those are just few for readability purposes. Anyways, I could do a "for" loop but it would do 500 loops everytime you click on the map... is there any other way to see if a certain string is in an array?

Try this:
if(blockedTile.indexOf("118") != -1)
{
// element found
}

As mentioned before, if your browser supports indexOf(), great!
If not, you need to pollyfil it or rely on an utility belt like lodash/underscore.
Just wanted to add this newer ES2016 addition (to keep this question updated):
Array.prototype.includes()
if (blockedTile.includes("118")) {
// found element
}

Some browsers support Array.indexOf().
If not, you could augment the Array object via its prototype like so...
if (!Array.prototype.indexOf)
{
Array.prototype.indexOf = function(searchElement /*, fromIndex */)
{
"use strict";
if (this === void 0 || this === null)
throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (len === 0)
return -1;
var n = 0;
if (arguments.length > 0)
{
n = Number(arguments[1]);
if (n !== n) // shortcut for verifying if it's NaN
n = 0;
else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0))
n = (n > 0 || -1) * Math.floor(Math.abs(n));
}
if (n >= len)
return -1;
var k = n >= 0
? n
: Math.max(len - Math.abs(n), 0);
for (; k < len; k++)
{
if (k in t && t[k] === searchElement)
return k;
}
return -1;
};
}
Source.

function in_array(needle, haystack){
var found = 0;
for (var i=0, len=haystack.length;i<len;i++) {
if (haystack[i] == needle) return i;
found++;
}
return -1;
}
if(in_array("118",array)!= -1){
//is in array
}

Use Underscore.js
It cross-browser compliant and can perform a binary search if your data is sorted.
_.indexOf
_.indexOf(array, value, [isSorted]) Returns the index at which value can be found in the array, or -1 if value is not present in the array.
Uses the native indexOf function unless it's missing. If you're
working with a large array, and you know that the array is already
sorted, pass true for isSorted to use a faster binary search.
Example
//Tell underscore your data is sorted (Binary Search)
if(_.indexOf(['2','3','4','5','6'], '4', true) != -1){
alert('true');
}else{
alert('false');
}
//Unsorted data works to!
if(_.indexOf([2,3,6,9,5], 9) != -1){
alert('true');
}else{
alert('false');
}

if(array.indexOf("67") != -1) // is in array

Assuming that you're only using the array for lookup, you can use a Set (introduced in ES6), which allows you to find an element in O(1), meaning that lookup is sublinear. With the traditional methods of .includes() and .indexOf(), you still may need to look at all 500 (ie: N) elements in your array if the item specified doesn't exist in the array (or is the last item). This can be inefficient, however, with the help of a Set, you don't need to look at all elements, and instead, instantly check if the element is within your set:
const blockedTile = new Set(["118", "67", "190", "43", "135", "520"]);
if(blockedTile.has("118")) {
// 118 is in your Set
console.log("Found 118");
}
If for some reason you need to convert your set back into an array, you can do so through the use of Array.from() or the spread syntax (...), however, this will iterate through the entire set's contents (which will be O(N)). Sets also don't keep duplicates, meaning that your array won't contain duplicate items.

I'd use a different data structure, since array seem to be not the best solution.
Instead of array, use an object as a hash-table, like so:
(posted also in jsbin)
var arr = ["x", "y", "z"];
var map = {};
for (var k=0; k < arr.length; ++k) {
map[arr[k]] = true;
}
function is_in_map(key) {
try {
return map[key] === true;
} catch (e) {
return false;
}
}
function print_check(key) {
console.log(key + " exists? - " + (is_in_map(key) ? "yes" : "no"));
}
print_check("x");
print_check("a");
Console output:
x exists? - yes
a exists? - no
That's a straight-forward solution. If you're more into an object oriented approach, then search Google for "js hashtable".

IMHO most compatible with older browsers
Array.prototype.inArray = function( needle ){
return Array(this).join(",").indexOf(needle) >-1;
}
var foods = ["Cheese","Onion","Pickle","Ham"];
test = foods.inArray("Lemon");
console.log( "Lemon is " + (test ? "" : "not ") + "in the list." );
By turning an Array copy in to a CSV string, you can test the string in older browsers.

Depending on the version of JavaScript you have available, you can use indexOf:
Returns the first index at which a given element can be found in the array, or -1 if it is not present.
Or some:
Tests whether some element in the array passes the test implemented by the provided function.
But, if you're doing this sort of existence check a lot you'd be better of using an Object to store your strings (or perhaps an object as well as the Array depending on what you're doing with your data).

in array example,Its same in php (in_array)
var ur_fit = ["slim_fit", "tailored", "comfort"];
var ur_length = ["length_short", "length_regular", "length_high"];
if(ur_fit.indexOf(data_this)!=-1){
alert("Value is avail in ur_fit array");
}
else if(ur_length.indexOf(data_this)!=-1){
alert("value is avail in ur_legth array");
}

var myArray = [2,5,6,7,9,6];
myArray.includes(2) // is true
myArray.includes(14) // is false

Why don't you use Array.filter?
var array = ['x','y','z'];
array.filter(function(item,index,array){return(item==YOURVAL)}).
Just copy that into your code, and here you go:
Array.prototype.inArray = function (searchedVal) {
return this.filter(function(item,index,array){return(item==searchedVal)}).length==true
}

You can try below code. Check http://api.jquery.com/jquery.grep/
var blockedTile = new Array("118", "67", "190", "43", "135", "520");
var searchNumber = "11878";
arr = jQuery.grep(blockedTile, function( i ) {
return i === searchNumber;
});
if(arr.length){ console.log('Present'); }else{ console.log('Not Present'); }
check arr.length if it's more than 0 means string is present else it's not present.

a little bit code from my side (custom function for Array):
Array.prototype.in_array = function (array) {
var $i = 0;
var type = typeof array;
while (this[$i]) {
if ((type == ('number') || type == ('string')) && array == this[$i]) {
return true;
} else if (type == 'object' && array instanceof Array && array.in_array(this[$i])) {
return true
}
$i++;
}
return false;
};
var array = [1, 2, 3, "a", "b", "c"];
//if string in array
if (array.in_array('b')) {
console.log("in array");
}
//if number in array
if (array.in_array(3)) {
console.log("in array");
}
// if one from array in array
if (array.in_array([1, 'b'])) {
console.log("in array");
}

I think the simplest way is that :
(118 in blockedTile); //is true

Related

Word Break algorithm

I'm trying to implement the "Word Break" algorithm.
Problem:
Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be segmented into a space-separated sequence of one or more dictionary words.
Note:
The same word in the dictionary may be reused multiple times in the segmentation.
You may assume the dictionary does not contain duplicate words.
Example:
Input: s = "leetcode", wordDict = ["leet", "code"]
Output: true
Explanation: Return true because "leetcode" can be segmented as "leet code".
My solution:
var wordBreak = function(s, wordDict) {
if(!wordDict || wordDict.length === 0)
return false;
while(wordDict.length > 0 || s.length > 0) {
const word = wordDict.shift();
const index = s.indexOf(word);
if(index === -1) {
return false;
}
s = s.substring(0, index) + s.substring(index+word.length, s.length);
}
return s.length === 0 && wordDict.length === 0 ? true : false;
};
It works for the example (input) above. However it fails for the input below.
Input: s = "applepenapple", wordDict = ["apple", "pen"]
Output: true
Explanation: Return true because "applepenapple" can be segmented as "apple pen apple".
Note that you are allowed to reuse a dictionary word.
How can I keep track of words that I already eliminate and check it at the end. This input above, the remaining s string contains "apple" which is in the word dictionary, so the output should be true.
Thanks
A simple Javascript solution.
This loops through the wordDict array and checks if each word exist in the str. If it doesn't that is when the indexOf the word return -1, the function returns false. However, if the words in the wordDict array are in the string, it returns true at the end of the for loop.
const wordBreak =(str, wordDict)=>{
if (!wordDict || wordDict.length === 0) return false
for(let i=0; I<wordDict.length; i++){
const dictIndex = str.indexOf(wordDict[i])
if(dictIndex === -1){
return false
}
}
return true
}
This is an interesting problem I met two years ago in a different context, i.e., query tokenization. In my case, the number of words in the dictionary was in the order of several million, therefore a recursive approach looking each time for a different word of the dictionary was not practicable. Furthermore, I needed to apply dynamic programming to solve the task for strict efficiency reasons.
First of all, I suggest you to use the AhoCorasick algorithm to find the words within your search string. The algorithm looks for an arbitrary number of patterns in a string in linear time in the length of the string regardless of the number of patterns to find (no more number of words times length of the string operation, indeed each find of a word in a string needs to scan the entire string..).
Luckily, I found a javascript implementation of the algorithm here.
Using the code linked above and dynamic programming to track the words appearing in your string, I wrote the following javascript solution:
function wordBreak(s, wordDict) {
const len = s.length;
const memoization_array_words = new Array(len).fill(null);
const memoization_array_scores = new Array(len).fill(0);
const wordScores = {};
wordDict.forEach(function(word) {
wordScores[word] = 1
});
automata = new AhoCorasick(wordDict);
results = automata.search(s);
results.forEach(function(result) {
// result[0] contains the end position
// result[1] contains the list of words ending in that position
const end_pos = result[0];
result[1].forEach(function(word) {
const prev_end_pos = end_pos - word.length;
const prev_score = (prev_end_pos == -1) ? 0 : memoization_array_scores[prev_end_pos];
const score = prev_score + wordScores[word];
if (score > memoization_array_scores[end_pos]) {
memoization_array_words[end_pos] = word;
memoization_array_scores[end_pos] = score;
}
});
});
if (memoization_array_words[len-1] == null) {
return false;
}
solution = []
var pos_to_keep = len - 1;
while (pos_to_keep >= 0) {
const word = memoization_array_words[pos_to_keep];
solution.push(word);
pos_to_keep -= word.length;
}
return solution.reverse()
}
where memoization_array_words and memoization_array_scores are filled left to right when we meet a word occurring after a previous one or at the beginning of the string s. The code should be autoesplicative, but if you need any explanation write me a comment, please.
As a plus, I associated a score to each word (here is 1 for simplicity) that allows you to distinguish between the different solutions. For instance, if you associate to each word an importance score, you will end up with the tokenization with the greatest score. In the code above, the tokenization with the highest number of words.
Extended version: I testing over the wordDict with some if there is one of the worde that beginns at the test-string (indexOf==0). If so I shorten the string about the length of the word and call the function recursivly with the shortened string. Otherwise the string is not splitable and I return false. I go this way on till an error occurs or the length of the string is 0 and I win because everything goes allright.
Remark: The error when the WordBreak is not clearly like with s= "cars" wordDict = ["car","ca","rs"] is now fixed. For this I calling in the some-methode the algorithm recursivly. So if one way stops before ending I go backwards and search for alternatives till I found one or there is no possibility left.
Remarks to; array.some
In an array.forEach there can't used a break without using some ugly tricks (like try...catch and throwing an error), so I could use the classic variant of the for-loop. But there exists the array.some method this loops like a forEach-loop but there had only one of the elements to be return true so the result is true.
Example:
const array = [1, 2, 3, 4, 5];
// checks whether an element is even
const even = (element) => element % 2 === 0;
console.log(array.some(even));
Here is the code of the working algorithm.
var wordBreak = function(s, wordDict) {
if (!wordDict || wordDict.length === 0) return false;
while (s.length > 0) {
let test = wordDict.some( (word,index) => {
if (s.indexOf(word)===0) {
s_new = s.substr(word.length);
return wordBreak(s_new, wordDict);
}
});
if (!test ) return false;
s=s_new;
}
if (s.length === 0) return true;
}
s = "leetcode"; wordDict = ["leet", "code"];
console.log(wordBreak(s, wordDict));
s = "applepenapple"; wordDict = ["apple", "pen"];
console.log(wordBreak(s, wordDict));
s= "cars"; wordDict = ["car","ca","rs"];
console.log(wordBreak(s, wordDict));
function wordBreak(dict, str){
if (!str){
return true;
}
for (const word of dict){
if (str.startsWith(word)){
return wordBreak(dict, str.substring(word.length, str.length))
}
}
return false;
}
You could also probably optimize the loop over dict by pre-sorting the array and using binary search, but hopefully this gets the point across.
If you'd be looking for a Dynamic Programming solution, we'd use an array for recording, and then we'd loop through and keep track of the word.
This'll pass through in JavaScript:
const wordBreak = function(s, wordDict) {
const len = s.length
const dp = new Array(len + 1).fill(false)
dp[0] = true
for (let i = 1; i < len + 1; i++) {
for (let j = 0; j < i; j++) {
if (dp[j] === true && wordDict.includes(s.slice(j, i))) {
dp[i] = true
break
}
}
}
return dp[s.length]
}
In Python, we would have used a list (which is similar to an array of JavaScript) with the same size as our string:
class Solution:
def wordBreak(self, s, words):
dp = [False] * len(s)
for i in range(len(s)):
for word in words:
k = i - len(word)
if word == s[k + 1:i + 1] and (dp[k] or k == -1):
dp[i] = True
return dp[-1]
Similarly in Java, we'd have used a boolean[]:
public final class Solution {
public static final boolean wordBreak(
String s,
List<String> words
) {
if (s == null || s.length() == 0) {
return false;
}
final int len = s.length();
boolean[] dp = new boolean[len];
for (int i = 0; i < len; i++) {
for (int j = 0; j <= i; j++) {
final String sub = s.substring(j, i + 1);
if (words.contains(sub) && (j == 0 || dp[j - 1])) {
dp[i] = true;
break;
}
}
}
return dp[len - 1];
}
}
Here is LeetCode's DP solution:
public class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
Set<String> wordDictSet=new HashSet(wordDict);
boolean[] dp = new boolean[s.length() + 1];
dp[0] = true;
for (int i = 1; i <= s.length(); i++) {
for (int j = 0; j < i; j++) {
if (dp[j] && wordDictSet.contains(s.substring(j, i))) {
dp[i] = true;
break;
}
}
}
return dp[s.length()];
}
}
References
For additional details, please see the Discussion Board which you can find plenty of well-explained accepted solutions in there, with a variety of languages including efficient algorithms and asymptotic time/space complexity analysis1, 2.

How do I replace integers in an array with a string when it's a function parameter in JavaScript?

What I am trying to do is make a function that takes user input, splits that input into an array of numbers, then replaces each number with a string depending on what the number is. It seems all this does now is return undefined, because it doesn't want to reassign the index to what It tell it to. I want to do this using a for loop or the forEach method if possible.
Here is my code so far:
function stringify(num){
var array = num;
for (i in array) {
if (array[i] == 2) {
array[i] = "x";
} else if (array[i] == 5) {
array[i] = "y";
} else {
array[i] = "meow"
}
return array;
}
}
Here is an example of what I want to eventually happen:
stringify(52527);
y x y x meow
You could map the new array by using an object for the wanted replacings.
function stringify(num) {
return Array.from(num, v => ({ 2: 'x', 5: 'y' }[v] || v));
}
console.log(stringify('5252'));
With default value
function stringify(num) {
var values = { 2: 'x', 5: 'y', default: 'meow' };
return Array.from(num, v => values[v] || values.default);
}
console.log(stringify('52527'));
Convert the input data to a string, and split the string to characters:
function stringify(num) {
var array = String(num).split('');
for (i in array) {
if (array[i] === '2') {
array[i] = "x";
} else if (array[i] === '5') {
array[i] = "y";
} else {
array[i] = "meow"
}
}
return array; // the return should be after the loop ends
}
console.log(stringify(52527));
Another solution would be to use a Array.map() to iterate after the split, and an object with the characters that should be replaced:
function stringify(num) {
var rep = { 2: 'x', 5: 'y' };
return String(num)
.split('')
.map(function(c) {
return rep[c] || 'meow';
});
}
console.log(stringify(52527));
I think you might have a couple of problems:
Using a for ... in loop for an array or an iterator isn't ideal; rather use the construction for (var i = 0; i < array.length; i += 1).
As other commenters have said, make sure you're converting the passed argument, which is a Number, into a String. My preference for doing this something like var numString = '' + num;. If you're using es6, you could also use the template literal notation:
var numString = `${num}`;
Be careful of using the double equal sign == versus the triple equals === to check equality. The double equal will do some arcane type-casting of its operands. Safer to stick with the triple equal unless you're sure.
Strings are immutable, which means that while you can access the values of their indices, you can't change those values. I would suggest creating a new array that you then join upon return:
function stringify(num) {
var numString = '' + num;
var ret = [];
for (var i = 0; i < numString.length; i += 1) {
if (numString[i] === '2') { // The index values will be strings, not numbers now
ret.push('x');
} else if (numString[i] === '5') {
ret.push('y');
} else {
ret.push('meow');
}
}
return ret.join(' ');
}
this results in:
stringify(52527);
y x y x meow

How to efficiently check if any substring in an array is contained in another string

I want to have something that checks if any substring in a list of strings is included in string. I have something that works, but I'm hoping there is something cleaner and more efficient, preferably just in one line I can call like if(string.contains(list.any)) or something.
var list = ['aa','bb','cc','dd'];
var string = "nygaard"; // true because "aa" is in "nygaard".
for (var i = 0; i < list.length; i++) {
if( string.indexOf( list[i] ) > -1 ) {
alert("True");
break;
}
}
var list = ['aa','bb','cc','dd'];
var string = "nygaard";
var patt = new RegExp(list.join('|'))
// regEx - /aa|bb|cc|dd/
patt.test(string)
//output true
Demo
Explanation
Dynamically create a regEx using new RegExp
for checking existance of multiple SubString we have | operator in RegEx
Use Array.join('|') to dynamically make a regExp like this aa|bb|cc
use test func to validate String
Edit - For Complex Cases - Problem is strings in list may have to be escaped for RegEx to work, Pointed By - #GabrielRatener
Compairing to my solu, #GabrielRatener's solution is better
var list = ['aa','bb','cc','dd', 'ab?', '(aa)'];
list = list.sort(function(a, b) {
if (a>b) return -1;
else if (a<b) return 1;
else return 0;
});
list = list.join(" ").replace(/[^\w\s]/g, function($1) {
return '\\' + $1
}).split(/\s/);
//["dd", "cc", "bb", "ab\?", "aa", "\(aa\)"]
//sorting needed to match "ab?" before single "a" as "b" will become optional
//due to "?"
//after processing
var string = "nygaard";
var patt = new RegExp(list.join('|')) // RegExp -> /dd|cc|bb|ab\?|aa|\(aa\)/
patt.test(string)
//true
Why not just put your loop in its own function you can call?
function stringContains(string, list) {
for (var i = 0; i < list.length; i++) {
if( string.indexOf( list[i] ) > -1 )
return true;
}
return false;
}
and then call it like this:
var list = ['aa','bb','cc','dd'];
var string = "nygaard";
if(stringContains(string, list))
alert("True");
If you're looking for a javascript library function, I don't believe there is one.
EcmaScript 6 is proposing a contains method for strings such that you could do this:
function stringContainsArray(str, array){
for (var i = 0; i < array.length; i++){
if (str.contains(array[i])){
return true;
}
}
return false;
}
var list = ['aa','bb','cc','dd'];
var string = "nygaard"; // true because "aa" is in "nygaard".
console.log(stringContainsArray(list));
// => true
Since implementation will likely remain spotty in the major browsers and other runtimes for the near future, you should add the following code for compatibility before the stringContainsArray function:
// String.prototype.contains will be implemented in
// the major browsers in the not too distant future
// this will add the same functionality to browsers
// or other runtimes that do not currently support it
if ( !String.prototype.contains ) {
String.prototype.contains = function() {
return String.prototype.indexOf.apply( this, arguments ) !== -1;
};
}
this may help: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/contains
You can also extend the string prototype to have a simple method:
String.prototype.containsArray = function(array){
return stringContainsArray(this, array);
}
Then you can simpy do:
"nygaard".containsArray(list);
// => true

A function that will search an array for letters and return the position in which those letters are

I've created a function that will search for individual letters from a string regardless of case and order. Here is what it looks like.
function match(string, pattern) {
string = string.toLowerCase();
pattern = pattern.toLowerCase();
var patternarray = pattern.split("");
for (i = 0; i < pattern.length; i++) {
if (patternarray[i] >= "a" && patternarray[i] <= "z") {
if (string.indexOf(patternarray[i]) == -1) return false
}
}
return true
}
Now I want to do a similar thing except this time I will be searching an array, and instead of returning true/false I would like to return a new array containing the places in which the string pops up.
For example, if my variable contents were ["Oranges","Apples","Bananas"] and my search was "n", the function would return [0,2]. I am a beginner with JavaScript so thorough explanation would be helpful.
Thanks!
function matchArray(array, pattern) {
var i,
len = array.length,
result = [];
for (i = 0; i < len; ++i) {
if (match(array[i], pattern)) {
result.push(i);
}
}
return result;
}
Underscorejs has a function that should take care of this for you. Just take a look at the filter function. It has the ability to return a new array with items that passed a truth test.
var aArray = _.filter(['asdf','ddd','afsf'], function(item){
return (item.indexOf('a') !== -1);
}

Recursively search for a value in global variables and its properties

Let's say that I want to search for a value, like 'StackOverflow', in all declared variables in window.
I can do it with this code:
function globalSearch(obj, value) {
for(var p in obj)
if(obj[p] == value)
return(p);
}
globalSearch(window, 'StackOverflow');
This code will return the name of a variable that have this value (or returns nothing).
So, if I have declared a variable with value 'StackOverflow', it will successfully find it.
My problem is that I want to go deeper and search thru window's objects (and its own nested objects) too, to achieve a result like this:
var x = 'StackOverflow' // returns 'x'
var y = { a : 'StackOverflow' } // returns 'y.a'
var z = { a : { b: 'StackOverflow' } } // returns 'z.a.b'
I'm having problems with inherited methods of Objects. Is there a way to do this?
Deep search but without the recursive function calls
Functional recursion has internal stack limits and wastes memory.
Additional features added
Recursive object protection in the form of a searched array; It doesn't use up too much memory of course as the objects are only stored as references.
Return true if the the object itself matches the value. Otherwise it would return '' which would match to false.
Arrays use angle-bracket notation.
The code
function globalSearch(startObject, value) {
var stack = [[startObject,'']];
var searched = [];
var found = false;
var isArray = function(test) {
return Object.prototype.toString.call( test ) === '[object Array]';
}
while(stack.length) {
var fromStack = stack.pop();
var obj = fromStack[0];
var address = fromStack[1];
if( typeof obj == typeof value && obj == value) {
var found = address;
break;
}else if(typeof obj == "object" && searched.indexOf(obj) == -1){
if ( isArray(obj) ) {
var prefix = '[';
var postfix = ']';
}else {
var prefix = '.';
var postfix = '';
}
for( i in obj ) {
stack.push( [ obj[i], address + prefix + i + postfix ] );
}
searched.push(obj);
}
}
return found == '' ? true : found;
}
Problems
Without passing the initial variable name into the function, we can't return the fully qualified variable name from the beginning. I can't think of a solution and I would be surprised if there was one.
Variable names with spaces are valid as the key to an object, as are other invalid variable names, it just means that the value must be addressed using angle-brackets. There are a couple of solutions I can think of. Regex check each variable name to make sure it's valid and use angle-brackets notation if it is not. The overriding problem with this is that the reg-ex is a page long. Alternatively, we could only use angle-brackets but this isn't really true to the OPs original question.
The indexOf call on the array 'searched' might be a bit heavy on very large objects but I can't yet think of an alternative.
Improvements
Apart from cleaning up the code a little, it would also be nice if the function returned an array of matches. This also raises another issue in that the returned array would not contain references to recursive objects. Maybe the function could accept a result format configuration parameter.
This should work. It uses recursion to achieve the result.
function globalSearch(obj, value) {
for(var p in obj)
if(obj[p] == value){
return(p);
}else if(typeof obj[p] == "object" && obj[p] != obj){
var te = globalSearch(obj[p], value);
if(te!=false){ return p + "." + te }
}
return false;
}
Make your solution recursive. If you have an object, call your function again.
function globalSearch(obj, value) {
for(var p in obj) {
if (obj[p] == value) {
return(p);
} else if (typeof obj[p] === "object") {
var recursiveCheck= globalSearch(obj[p], value);
if (recursiveCheck) {
return p + "." + recursiveCheck;
}
}
}
}
globalSearch(window, 'StackOverflow');
I bet most browsers will hit a warning for too much looping.
This code, based on the other answer, allows for all possible value matches to be found.
function globalSearch(startObject, value, returnFirstResult = false) {
var stack = [[startObject,'']];
var searched = [];
var found = new Set();
var isArray = function(test) {
return Object.prototype.toString.call( test ) === '[object Array]';
}
while(stack.length) {
var fromStack = stack.pop();
var obj = fromStack[0];
var address = fromStack[1];
if( typeof obj == typeof value && obj == value) {
if (returnFirstResult) {
return address == '' ? false : address;
}
found.add(address)
}if(typeof obj == "object" && searched.indexOf(obj) == -1){
if ( isArray(obj) ) {
var prefix = '[';
var postfix = ']';
}else {
var prefix = '.';
var postfix = '';
}
for( i in obj ) {
stack.push( [ obj[i], address + prefix + i + postfix ] );
}
searched.push(obj);
}
}
return Array.from(found);
}

Categories