AnswerBun.com

What is wrong in this sorting array skipping some elements?

I have array of objects. I want sort it leave some elements in the same position (with b="NOT")

var a=[{a:1,b:"YES"},{a:2,b:"YES"},{a:5,b:"NOT"},{a:0,b:"NOT"},{a:0,b:"YES"}]

function sortc(x,y){

  if (x.b=="NOT" || y.b=="NOT")
    return Infinity ;
     
  return (Number(x.a)-Number(y.a))
                 
}

console.log(a.sort(sortc));

the result is :

0: {a: 1, b: "YES"}
1: {a: 2, b: "YES"}
2: {a: 5, b: "NOT"}
3: {a: 0, b: "NOT"}
4: {a: 0, b: "YES"}

The expected result was ( with sort components with b="YES".) :

{ "a": 0, "b": "YES" }
{ "a": 1, "b": "YES" }
{ "a": 5, "b": "NOT" }
{ "a": 0, "b": "NOT" }
{ "a": 2, "b": "YES" } 

Stack Overflow Asked by Eymerich on December 26, 2020

2 Answers

2 Answers

You cannot only sort some items using the Array#sort() method - you either sort all or none. You don't define the position of the items, either - you only have to define their relationship to other items and the sorting algorithm will take care of the rest.

What you can do as a workaround is

  1. Extract all items that should be sorted.
  2. Sort them.
  3. Go over the original array and only replace anything that should be sorted, leave the rest of the items in their place.

var a = [
  { a: 1, b: "YES" }, 
  { a: 2, b: "YES" },
  { a: 5, b: "NOT" }, 
  { a: 0, b: "NOT" }, 
  { a: 0, b: "YES" }
]

//get only `b: "YES"` items
const dataToSort = a.filter(item => item.b === "YES");

//sort them
dataToSort.sort((x, y) => x.a - y.a);

//replace only items that need to be sorted
const it = dataToSort.values()
for (let i = 0; i < a.length; i++) {
  if (a[i].b === "NOT")
    continue;
    
  a[i] = it.next().value;
}

console.log(a);

For the record, the final loop can just be replaced with even shorter with more iterator usage, although it might be slightly more confusing:

const it = dataToSort.values()
for (const [key, item] of a.entries()) { //use the key-value iterator from the array
  if (item.b === "NOT")
    continue;
    
  [a[key]] = it; //array destructuring internally advances an iterator
}

var a = [
  { a: 1, b: "YES" }, 
  { a: 2, b: "YES" },
  { a: 5, b: "NOT" }, 
  { a: 0, b: "NOT" }, 
  { a: 0, b: "YES" }
]

//get only `b: "YES"` items
const dataToSort = a.filter(item => item.b === "YES");

//sort them
dataToSort.sort((x, y) => x.a - y.a);

//replace only items that need to be sorted
const it = dataToSort.values()
for (const [key, item] of a.entries()) {
  if (item.b === "NOT")
    continue;
    
  [a[key]] = it;
}

console.log(a);


Finally, this can be made somewhat more convenient with helper generator function and few small utility functions

/*  library code  */

const transformArg = transform => f => (...args) => f(transform(...args));

function* filter(predicate, it) {
  for (const item of it) {
    if (predicate(item))
      yield item;
  }
}

/*  /library code  */

var a = [
  { a: 1, b: "YES" }, 
  { a: 2, b: "YES" },
  { a: 5, b: "NOT" }, 
  { a: 0, b: "NOT" }, 
  { a: 0, b: "YES" }
]

/* helpers */
//extract the `b` key in this case so we don't need to repeat it. 
const getSortableAttribute = transformArg(({b}) => b);
//get the value from key-value pair
const getValue = transformArg(([, value]) => value);
//check if the attribute is "YES"
const isSortable = getSortableAttribute(attr => attr === "YES");

const dataToSort = a.filter(isSortable);

dataToSort.sort((x, y) => x.a - y.a);

const it = dataToSort.values()
//iterate only over sortable key-value pairs by re-using the `isSortable` filter
for (const [key, item] of filter(getValue(isSortable), a.entries())) {
  [a[key]] = it;
}

console.log(a);

Correct answer by VLAZ on December 26, 2020

This is an approach by using sort directly, but shaping the access with a Proxy for length and the indices.

const
    sortOnly = (array, indices) => new Proxy(array, {
        get (target, prop) {
            if (isFinite(prop)) return target[indices[prop]];
            if (prop === 'length') return indices.length;
            return target[prop];
        },
        set (target, prop, receiver) {
            target[indices[prop]] = receiver;
            return true;
        }
    }),
    array = [{ a: 1, b: "YES" }, { a: 2, b: "YES" }, { a: 5, b: "NOT" }, { a: 0, b: "NOT" }, { a: 0, b: "YES" }];

sortOnly(array, [...array.keys()].filter(i => array[i].b !== 'NOT'))
    .sort((a, b) => a.a - b.a)

console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Answered by Nina Scholz on December 26, 2020

Add your own answers!

Related Questions

How to Deserialize a list of objects from json in flutter

8  Asked on January 28, 2021 by gainz

     

How to pass input variable in structure directive?

1  Asked on January 27, 2021 by alice-messis

 

How to iterate over a list of floats in python

4  Asked on January 27, 2021 by joeyhoward988

 

Can I run docker system prune -a without downtime

1  Asked on January 27, 2021 by aswin-george

 

Calculating total Price of groceries with execptions in Python

4  Asked on January 27, 2021 by shemtheultimate

 

handling multiple useState inside conditional ternary

2  Asked on January 27, 2021 by kachi-cheong

     

react-native existing app crash on Android 4.1

0  Asked on January 27, 2021 by s-leg3ndz

     

HTML table widths set proportionally

1  Asked on January 27, 2021 by mayur-arora

   

Alsa issues on Raspberry pi

1  Asked on January 27, 2021 by suraj-hebbar-shankar

 

How to merge dictionaries with the same key and value in Python

1  Asked on January 26, 2021 by arbin-bulaybulay

 

AJAX switching HTML

1  Asked on January 26, 2021 by mimi

       

Using request to return a json value

1  Asked on January 26, 2021 by gta-sprx

 

Ask a Question

Get help from others!

© 2022 AnswerBun.com. All rights reserved.