סינון טקסט חופשי בarray js
-
למה יש בזה שגיאה? (החלפתי לפונקציה כמו כאן)
arr = [ {A:1,B:2}, {A:2,B:'world'}, {A:3,B:2,C: 1}, {A:4,B:5}, {A:1,B:2}]; function filterByAnyField(arr, search){ return arr.filter(a => { for(var prop in a) if(a[prop].includes(search)) //a[prop] === search) return true; }); } var filtered = filterByAnyField(arr, "world"); console.log(filtered);
-
בגלל שinclude קיימת רק עבור שדות שהם טקסטואליים, שהם מטיפוס string.
לשדות המספריים אין כזו מתודה. תוכל פשוט לבדוק אם היא קיימת לפני הבדיקה, ככה:function filterByAnyField(arr, search){ return arr.filter(a => { for(var prop in a) if(a[prop] == search || (a[prop].includes && a[prop].includes(search))) return true; }); }
-
החלק של a[prop] == search בא לחסוך בביצועים: אם זה שווה אין טעם לבדוק אם זה מכיל (זה רק לקוד נכון. השיפור הוא לגמרי תיאורטי, מאוד מסתבר שבדיקת ההכלה טובה מספיק).
ערכתי כעת משלושה סימני שויון לשניים, כי תמיד הsearch יגיע כטקסט, ורוצים גם להשוות למספרים. -
דבר ראשון, בדוגמא הזו זה לא עובד על כל הטקסט
דבר שני, באתר שאני עובד עליו, יש את השגיאה הזו. זה לכאו' יותר קשור ל-VUE, אבל תכלס אין לי מושג איך מתמודדים איתו.
vue.js:634 [Vue warn]: Error in render: "TypeError: Cannot read property 'includes' of null" (found in <Root>) warn @ vue.js:634 logError @ vue.js:1893 globalHandleError @ vue.js:1888 handleError @ vue.js:1848 Vue._render @ vue.js:3553 updateComponent @ vue.js:4067 get @ vue.js:4478 run @ vue.js:4553 flushSchedulerQueue @ vue.js:4311 (anonymous) @ vue.js:1989 flushCallbacks @ vue.js:1915 Promise.then (async) timerFunc @ vue.js:1942 nextTick @ vue.js:1999 queueWatcher @ vue.js:4403 update @ vue.js:4543 notify @ vue.js:745 reactiveSetter @ vue.js:1070 getdatabusiness.onreadystatechange @ jobsnew.php:785 XMLHttpRequest.send (async) getdatabusiness @ jobsnew.php:801 (anonymous) @ jobsnew.php:776 vue.js:1897 TypeError: Cannot read property 'includes' of null at jobsnew.php:552 at Array.filter (<anonymous>) at filtertextByAnyField (jobsnew.php:550) at Vue.filtered_databusiness (jobsnew.php:694) at Watcher.get (vue.js:4478) at Watcher.evaluate (vue.js:4583) at Proxy.computedGetter (vue.js:4832) at Proxy.eval (eval at createFunction (vue.js:11649), <anonymous>:3:3388) at Vue._render (vue.js:3551) at Vue.updateComponent (vue.js:4067)
-
תעזוב לרגע את השגיאה ותתמקד בעובדה שהוא לא מוצא את המילה world.
תנסה להבין מה שונה בקלט שלך מהקלט שלי, כרמז לתשובה, שים מספרים שונים בכל מאפייני הA למשל, ובדוק אח"כ אם כל אחד מהם מגיב לחיפוש.
מעניין אותי אם אתה עולה על ההבדל שיחדד לך את השאלה ותיתן לך גם כיוון לתשובה. -
ככל והוא ברמה העליונה של האיברים הוא מחזיר אבל לא מתחת לזה.
(https://jsfiddle.net/8ps67eu4/) -
@chagold נכון מאוד. אתה מבין אבל את הרציונל?
אתה צריך להבין שמערך הפנימי הוא כולו על איבריו איבר בודד במערך העליון. וכאיבר יחיד, הוא נבדק בדיוק כמו היתר: כל מאפיין שלו נסרק (אין לו אפילו אחד) והוא תמיד יימצא כלא מתאים. נניח והוא היה מתאים, הוא היה חוזר כולו כחיובי, שוב יחד עם כל האובייקטים שהוא מכיל.
אם אתה מבין את זה, השאלה תהיה איך מחפשים גם במערכים מקוננים. יש לנו שלוש אפשרויות: א. "השטחה" למערך אחד מראש, אני מבין שזה לא מתאים לסיטואציה שלך, ב. השטחה כל חיפוש, ג. מתודה שלא משתמשת כלל בreduce. -
יש לציין שהשטחה תעזור רק לתת מערך, זה לא יהיה רקורסיבי, הנה איך הקוד עם השטחה בעזרת array.flat:
function filtertextByAnyField(arr, search){ return arr.flat().filter(a => { for(var prop in a) if(a[prop] == search || (a[prop].includes && a[prop].includes(search))) return true; }); }
פונקציה מותאמת אישית לעומת זאת תעבוד גם רקורסיבית:
function filtertextByAnyField(arr, search, result) { result = result || []; for (var item of arr) if (Array.isArray(item)) filtertextByAnyField(item, search, result); else if(checkSingleItem(item, search)) result.push(item); return result; } function checkSingleItem(item, search){ for (var prop in item) if (item[prop] == search || (item[prop].includes && item[prop].includes(search))) return true }
-
@dovid
דבר ראשון,new Array(1000000).fill({A:'אין לי מילים'})
דבר שני גיליתי את התקלה שגרמה לשגיאה. היה שם כמה nullים
שיניתי את הקוד ל-
function checkSingleItem(item, search){ for (var prop in item) if ( (item[prop] != null) && (item[prop] == search || (item[prop].includes && item[prop].includes(search)))) return true }
.
-
סתם הערה כללית:
מומלץ בJS לא להשתמש בFOR IN, אלא ב Object.keys ועל זה להריץ את הפונקציה forEach ככה:Object.keys(myObject).forEach(key => { let temp = myObject[key]; // כאן לעשות מה שרוצים });
הסיבה היא שלולאת for in רצה על כל המפתחות של האובייקט, כולל אלו שמגיעים דרך הprototype, דהיינו אלו שהוא יורש מהאובייקט הקדמון ובד"כ אתה רוצה לרוץ רק על המפתחות של האובייקט שאתה יצרת.
Object.keys רץ רק על המפתחות של האובייקט הנוכחי, ולכן זה יותר מומלץ. (אא"כ יש לך צורך ספציפי לרוץ גם על הפרוטוטייפ, שאז כמובן אתה צריך להשתמש בfor in).
כמו כן, היום עדיף בכלל לא להשתמש ב var אלא בlet, נראה לי שכבר כל הדפדפנים המודרנים תומכים בזה היום.